Skip to content

Instantly share code, notes, and snippets.

@buzzdecafe
Forked from CrossEye/Functor.js
Last active October 18, 2023 07:28
Show Gist options
  • Select an option

  • Save buzzdecafe/5721205 to your computer and use it in GitHub Desktop.

Select an option

Save buzzdecafe/5721205 to your computer and use it in GitHub Desktop.

Revisions

  1. buzzdecafe revised this gist Jun 6, 2013. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,4 @@
    // These need to be registered from general to specific.
    // The alternative I can see is to use a prototype-based solutions as done in:
    // https://github.com/loop-recur/typeclasses/blob/master/functor.js
    // relies on NFEs to lookup correct fmap. not great.

    Functor({key: "Array", obj: Array, fmap: function(f, arr){
    return arr.map(function(x){return f(x);});
  2. buzzdecafe revised this gist Jun 6, 2013. 3 changed files with 15 additions and 19 deletions.
    22 changes: 9 additions & 13 deletions Functor.js
    Original file line number Diff line number Diff line change
    @@ -1,20 +1,16 @@
    (function(global) {
    var types = function(obj) {
    throw new TypeError("fmap called on unregistered type: " + obj);
    };

    // inefficient as hell, but as long as there aren't too many types...
    global.Functor = function(type, defs) {
    var oldTypes = types;
    types = function(obj) {
    if (type.prototype.isPrototypeOf(obj)) {
    return defs;
    }
    return oldTypes(obj);
    }
    global.Functor = function(conf) {
    Functor.types[conf.key] = {
    obj: conf.obj,
    fmap: conf.fmap
    };
    };

    Functor.types = {};

    global.fmap = curry(function(f, obj) {
    return types(obj).fmap(f, obj);
    var key = obj.constructor.name; // or even nastier: obj.constructor.toString().match(/function (\w*)/)[1]
    return Functor.types[key].fmap(f, obj);
    });
    }(this));
    4 changes: 2 additions & 2 deletions dependencies.js
    Original file line number Diff line number Diff line change
    @@ -19,12 +19,12 @@ var compose = function(f, g) {
    };
    };

    var Maybe = function(val) {
    var Maybe = function Maybe(val) {
    if (!(this instanceof Maybe)) {return new Maybe(val);}
    this.val = val;
    };

    var Either = function(left, right) {
    var Either = function Either(left, right) {
    if (!(this instanceof Either)) {return new Either(left, right);}
    this.left = left;
    this.right = right;
    8 changes: 4 additions & 4 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -2,19 +2,19 @@
    // The alternative I can see is to use a prototype-based solutions as done in:
    // https://github.com/loop-recur/typeclasses/blob/master/functor.js

    Functor(Array, {fmap: function(f, arr){
    Functor({key: "Array", obj: Array, fmap: function(f, arr){
    return arr.map(function(x){return f(x);});
    }});

    Functor(Function, {fmap: function(f, g) {
    Functor({key: "Function", obj: Function, fmap: function(f, g) {
    return compose(f, g);
    }});

    Functor(Maybe, {fmap: function(f, maybe) {
    Functor({key: "Maybe", obj: Maybe, fmap: function(f, maybe) {
    return (maybe.val == null) ? maybe : Maybe(f(maybe.val));
    }});

    Functor(Either, {fmap: function(f, either) {
    Functor({key: "Either", obj: Either, fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }});

  3. @CrossEye CrossEye revised this gist Jun 5, 2013. 1 changed file with 16 additions and 23 deletions.
    39 changes: 16 additions & 23 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -1,36 +1,29 @@
    // These need to be registered from general to specific.
    // The alternative I can see is to use a prototype-based solutions as done in:
    // https://github.com/loop-recur/typeclasses/blob/master/functor.js
    Functor(Array, {
    fmap: function(f, arr){
    return arr.map(function(x){
    return f(x);
    });
    }
    });

    Functor(Function, {
    fmap: function(f, g){ return compose(f, g); }
    });

    Functor(Maybe, {
    fmap: function(f, maybe) {
    return (maybe.val == null) ? maybe : Maybe(f(maybe.val));
    }
    });

    Functor(Either, {
    fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }
    });
    Functor(Array, {fmap: function(f, arr){
    return arr.map(function(x){return f(x);});
    }});
    Functor(Function, {fmap: function(f, g) {
    return compose(f, g);
    }});

    Functor(Maybe, {fmap: function(f, maybe) {
    return (maybe.val == null) ? maybe : Maybe(f(maybe.val));
    }});

    Functor(Either, {fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }});

    var plus1 = function(n) {return n + 1;};
    var times2 = function(n) {return n * 2;};

    console.log(fmap(plus1, [2, 4, 6, 8])); //=> [3, 5, 7, 9]
    console.log(fmap(plus1, Maybe(5))); //=> Maybe(6)
    console.log(fmap(plus1, Maybe(null))); //=> Maybe(null)
    console.log(fmap(plus1, times2)(3)); //=> 7 (== 3 * 2 + 1)
    console.log(fmap(plus1, times2)(3)); //=> 7 (= 3 * 2 + 1)
    console.log(fmap(plus1, Either(10, 20))); //=> Either(10, 21)
    console.log(fmap(plus1, Either(10, null))); //=> Either(11, null)
  4. @CrossEye CrossEye revised this gist Jun 5, 2013. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,6 @@
    // These need to be registered from general to specific.
    // The alternative I can see is to use a prototype-based solutions as done in:
    // https://github.com/loop-recur/typeclasses/blob/master/functor.js
    Functor(Array, {
    fmap: function(f, arr){
    return arr.map(function(x){
  5. @CrossEye CrossEye revised this gist Jun 5, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Functor.js
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,6 @@
    (function(global) {
    var types = function(obj) {
    throw new TypeError("fmap called on unknown type: " + obj);
    throw new TypeError("fmap called on unregistered type: " + obj);
    };

    // inefficient as hell, but as long as there aren't too many types...
  6. @CrossEye CrossEye revised this gist Jun 5, 2013. 1 changed file with 6 additions and 8 deletions.
    14 changes: 6 additions & 8 deletions Functor.js
    Original file line number Diff line number Diff line change
    @@ -1,22 +1,20 @@
    (function(global) {

    var types = function(f, obj) {
    var types = function(obj) {
    throw new TypeError("fmap called on unknown type: " + obj);
    };

    // inefficient as hell, but as long as there aren't too many types...
    global.Functor = function(type, defs) {
    var oldTypes = types;
    types = function(f, obj) {
    types = function(obj) {
    if (type.prototype.isPrototypeOf(obj)) {
    return defs.fmap(f, obj);
    return defs;
    }
    return oldTypes(f, obj);
    return oldTypes(obj);
    }
    };

    global.fmap = curry(function(f, obj) {
    return types(f, obj);
    return types(obj).fmap(f, obj);
    });

    }(this));
    }(this));
  7. @CrossEye CrossEye revised this gist Jun 5, 2013. 1 changed file with 6 additions and 6 deletions.
    12 changes: 6 additions & 6 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,12 @@ Functor(Maybe, {
    }
    });

    Functor(Either, {
    fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }
    });

    var plus1 = function(n) {return n + 1;};
    var times2 = function(n) {return n * 2;};

    @@ -25,9 +31,3 @@ console.log(fmap(plus1, Maybe(null))); //=> Maybe(null)
    console.log(fmap(plus1, times2)(3)); //=> 7 (== 3 * 2 + 1)
    console.log(fmap(plus1, Either(10, 20))); //=> Either(10, 21)
    console.log(fmap(plus1, Either(10, null))); //=> Either(11, null)

    Functor(Either, {
    fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }
    });
  8. @CrossEye CrossEye revised this gist Jun 5, 2013. 2 changed files with 10 additions and 10 deletions.
    10 changes: 0 additions & 10 deletions examples.js
    Original file line number Diff line number Diff line change
    @@ -1,10 +0,0 @@
    var plus1 = function(n) {return n + 1;};
    var times2 = function(n) {return n * 2;};

    console.log(fmap(plus1, [2, 4, 6, 8])); //=> [3, 5, 7, 9]
    console.log(fmap(plus1, Maybe(5))); //=> Maybe(6)
    console.log(fmap(plus1, Maybe(null))); //=> Maybe(null)
    console.log(fmap(plus1, times2)(3)); //=> 7 (== 3 * 2 + 1)
    console.log(fmap(plus1, Either(10, 20))); //=> Either(10, 21)
    console.log(fmap(plus1, Either(10, null))); //=> Either(11, null)

    10 changes: 10 additions & 0 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -16,6 +16,16 @@ Functor(Maybe, {
    }
    });

    var plus1 = function(n) {return n + 1;};
    var times2 = function(n) {return n * 2;};

    console.log(fmap(plus1, [2, 4, 6, 8])); //=> [3, 5, 7, 9]
    console.log(fmap(plus1, Maybe(5))); //=> Maybe(6)
    console.log(fmap(plus1, Maybe(null))); //=> Maybe(null)
    console.log(fmap(plus1, times2)(3)); //=> 7 (== 3 * 2 + 1)
    console.log(fmap(plus1, Either(10, 20))); //=> Either(10, 21)
    console.log(fmap(plus1, Either(10, null))); //=> Either(11, null)

    Functor(Either, {
    fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
  9. @CrossEye CrossEye created this gist Jun 5, 2013.
    22 changes: 22 additions & 0 deletions Functor.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,22 @@
    (function(global) {

    var types = function(f, obj) {
    throw new TypeError("fmap called on unknown type: " + obj);
    };

    // inefficient as hell, but as long as there aren't too many types...
    global.Functor = function(type, defs) {
    var oldTypes = types;
    types = function(f, obj) {
    if (type.prototype.isPrototypeOf(obj)) {
    return defs.fmap(f, obj);
    }
    return oldTypes(f, obj);
    }
    };

    global.fmap = curry(function(f, obj) {
    return types(f, obj);
    });

    }(this));
    31 changes: 31 additions & 0 deletions dependencies.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    var curry = function(fn) {
    var arity = fn.length;
    var f = function(args) {
    return function () {
    var newArgs = (args || []).concat([].slice.call(arguments, 0));
    if (newArgs.length >= arity) {
    return fn.apply(this, newArgs);
    }
    else {return f(newArgs);}
    };
    };

    return f([]);
    };

    var compose = function(f, g) {
    return function() {
    return f.call(this, (g.apply(this, arguments)));
    };
    };

    var Maybe = function(val) {
    if (!(this instanceof Maybe)) {return new Maybe(val);}
    this.val = val;
    };

    var Either = function(left, right) {
    if (!(this instanceof Either)) {return new Either(left, right);}
    this.left = left;
    this.right = right;
    };
    10 changes: 10 additions & 0 deletions examples.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    var plus1 = function(n) {return n + 1;};
    var times2 = function(n) {return n * 2;};

    console.log(fmap(plus1, [2, 4, 6, 8])); //=> [3, 5, 7, 9]
    console.log(fmap(plus1, Maybe(5))); //=> Maybe(6)
    console.log(fmap(plus1, Maybe(null))); //=> Maybe(null)
    console.log(fmap(plus1, times2)(3)); //=> 7 (== 3 * 2 + 1)
    console.log(fmap(plus1, Either(10, 20))); //=> Either(10, 21)
    console.log(fmap(plus1, Either(10, null))); //=> Either(11, null)

    23 changes: 23 additions & 0 deletions usage.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    Functor(Array, {
    fmap: function(f, arr){
    return arr.map(function(x){
    return f(x);
    });
    }
    });

    Functor(Function, {
    fmap: function(f, g){ return compose(f, g); }
    });

    Functor(Maybe, {
    fmap: function(f, maybe) {
    return (maybe.val == null) ? maybe : Maybe(f(maybe.val));
    }
    });

    Functor(Either, {
    fmap: function(f, either) {
    return (either.right == null) ? Either(f(either.left), null) : Either(either.left, f(either.right));
    }
    });