Skip to content

Instantly share code, notes, and snippets.

@JackNova
Created December 19, 2012 18:28
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JackNova/4339141 to your computer and use it in GitHub Desktop.
Save JackNova/4339141 to your computer and use it in GitHub Desktop.
Monads Implementation in javascript, as seen in crockford presentation at yui conf 2012
//BASIC PIECES, 3 functions: unit, bind and the bind argument
//function unit(value)
//function bind(monad, function(value))
//all three functions return a monad
/* The unit function is a constructor (returns a monad object)
* The magic is in the bind function
*
* There are AXIOMS:
* bind(unit(value)), f) === f(value)
* bind(monad, unit) === monad
* bind(bind(monad, f), g) === bind(monad, function (value) { return bind(f(value), g); })
*/
//to avoid defining lots of bind function for different kind of monads
//and manage naming interference
//we turn the function into a method
//to define many different monads with similar properties
//various languages like common lisp have a macro system.
//javascript does not but does have functions and dynamic objects
//so you can get MACROIDS
function MONAD() {
return function unit(value) {
var monad = Object.create(null);
monad.bind = function (func) {
return func(value);
};
return monad;
};
}
//returns a unit function (unit function return in Haskell)
//it creates a monad that inherits nothing
//it puts a bind method in that monad, and the bind method
//will take a function as an argument and return the value of calling that function with the value
//that was passed in to the unit constructor. Then it returns a monad.
//in this for it is called the IDENTITY MONAD: the value that got passed into the unit
//will be the thing that gets passed into all the bind functions.
var identity = MONAD();
var monad = identity("Hello world");
monad.bind(alert);
//let's rewrite axioms in the object oriented form, in the method form.
unit(value).bind(f) === f(value)
monad.bind(unit) === monad
monad.bind(f).bind(g) === monad.bind(function (value) {
return f(value).bind(g);
})
//let's compare something:
bind(bind(monad, f), g)
monad.bind(f).bind(g) //Ajax Monad
//from
monad.bind(func)
//to
monad.method()
monad.bind(func, [a, b, c]) //second argument who will optionally take an array of parameters
monad.method(a, b, c)
//MACROID MODIFICATIONS
function MONAD() {
var prototype = Object.create(null);
function unit(value) {
var monad = Object.create(prototype);
monad.bind = function (func, args) {
return func.apply(undefined, //this is bad, in the next edition of javascript ES6 we will probably have
[value].concat(Array.prototype //a method called SPAT that will simplify things
.slice.apply(args || []))); // -> return func(value, ...args)
};
return monad;
};
}
function MONAD() {
var prototype = Object.create(null);
function unit(value) {
var monad = Object.create(prototype);
monad.bind = function (func, args) {
return func(value, ...args);
};
return monad;
}
unit.method = function (name, func) {
prototype[name] = func;
return unit;
};
}
//OR BETTER
function MONAD() {
var prototype = Object.create(null);
function unit(value) {
var monad = Object.create(prototype);
monad.bind = function (func, args) {
return func(value, ...args);
};
return monad;
}
//this doesen't take only a function that knows about monads but any function
//and guaratees that the result is a monad
unit.lift = function (name, func) {
prototype[name] = function (...args) {
return unit(this.bind(func, args));
}
return unit;
};
return unit;
}
var ajax = MONAD()
.lift('alert', alert);
var monad = ajax("Hello world.");
monad.alert();
//the MAYBE MONAD
//similar to NaN
function MONAD(modifier) {
var prototype = Object.create(null);
function unit(value) {
var monad = Object.create(prototype);
monad.bind = function (func, args) {
return func(value, ...args);
};
if (typeof modifier === 'function') {
modifier(monad, value);
}
return monad;
}
}
var maybe = MONAD(function (monad, value) {
if (value === null || value === undefined) {
monad.is_null = true;
monad.bind = function () {
return monad;
};
}
});
var monad = maybe(null); //nothing happens
monad.bind(alert);
//PROMISES
//inspired from FUTURES from the ACTOR MODEL
//resolve the problems of TURN BASED SYSTEMS (nested callbacks)
//a promise is an object that represents a possible future value.
//every promise has a corresponding resolver that is used to ultimately assign value to the promise
//a promise can have one of three states: kept, broken or pending
//a promise can accept functions that will be called with th evalue once the promise has been kept or broken.
//promise.when(success, failure) returns another promise for the result of your success function.
var my_vow = VOW.make();
.keep(value)
.break(reason)
.promise
.when(kept, broken)
//FILESYSTEM API
read_file(name)
.when(function success(string) {
...
}, failure)
@marco-faustinelli
Copy link

Dario, amico mio. Sto provando ad andare OLTRE quanto detto da Doug, creandomi delle mie applicazioni di questo benedetto macroide. Solo provare ad estendere questa "ajax monad" mi fa venire i capogiri. Ti va di unire gli sforzi?
https://github.com/Muzietto/monad
Comunque buona giornata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment