Skip to content

Instantly share code, notes, and snippets.

@elclanrs
Last active January 30, 2017 00:21
Show Gist options
  • Save elclanrs/8034102 to your computer and use it in GitHub Desktop.
Save elclanrs/8034102 to your computer and use it in GitHub Desktop.
Simple monads in JavaScript with `do` syntax
var fluent = function(f) {
return function() {
f.apply(this, arguments);
return this;
};
};
var Maybe = {
unit: fluent(function(x) {
this.x = x;
}),
bind: function(f) {
if (this.isNothing) {
return this.nothing();
} else if (this.isJust) {
return f.call(this, this.x);
}
},
nothing: fluent(function(x) {
this.x = null;
this.isNothing = true;
this.toString = function() {
return 'Nothing';
};
}),
just: fluent(function(x) {
this.x = x;
this.isJust = true;
this.toString = function() {
return 'Just: '+ this.x;
};
}),
valueOf: function() {
return this.x;
}
};
var trim = function(s) {
return s.trim();
};
var replace = function(regex, replacement) {
return function(s) {
return s.replace(regex, replacement);
};
};
var doM = function(f) {
var unit = /return (.+)$/
, backcall = /(\w+) <- (.+)/
, end = '';
return Function(f
.toString()
.split(/[\n;]/)
.slice(1,-1)
.map(trim)
.filter(Boolean)
.reduce(function(a, b) {
return a +';\n'+ b
.replace(unit, 'return this.unit($1)')
.replace(backcall, function(_, a, b) {
end += '});';
return 'return '+ b +'.bind(function('+ a +'){';
});
}, '')
.split(/\n/)
.slice(1)
.map(replace(/\{;$/, '{'))
.join('') + end
)();
};
// Example
// ----------------------------------------
var add = function(x, y) {
if (x == null || y == null) {
return Maybe.nothing();
}
return Maybe.just(x + y);
};
// Success
var result = doM(function() {
x <- add(1, 2);
y <- add(x, 2);
z <- add(x, y);
return x * y * z;
});
console.log(result.toString()); //=> Just 120
// Fail
var result = doM(function() {
x <- add(1, 2);
y <- add(x, null);
z <- add(x, y);
return x * y * z;
});
console.log(result.toString()); //=> Nothing
@pkamenarsky
Copy link

This is genius!

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