Skip to content

Instantly share code, notes, and snippets.

@towry
Last active July 6, 2017 10:00
Show Gist options
  • Save towry/a2205dfd7c04b85e2963fff209bd3b61 to your computer and use it in GitHub Desktop.
Save towry/a2205dfd7c04b85e2963fff209bd3b61 to your computer and use it in GitHub Desktop.
explain monad in js.
/*!
https://blog.jcoglan.com/2011/03/05/translation-from-haskell-to-javascript-of-selected-portions-of-the-best-introduction-to-monads-ive-ever-read/
this is a function with side effect, to dealing with side effect,
we can format it into return value, because pure function can only
have input and output (return) effect to outside world.
```js
// signature: x -> y
var sin = function (x) {
console.log('called from sin');
return Math.sin(x);
}
// signature: x -> (y, y)
var sinPure = function (x) {
return [Math.sin(x), 'called from sin'];
}
```
So here the second value in container is string `'called from sin'`,
we can think it as side effect. If we are performing IO task in such
function, we can wrap the IO result into the return value.
*/
// with side effect
var sin = function (x) {
return [Math.sin(x), "called from sin"];
}
var cube = function (x) {
return [x * x * x, "called from cube"];
}
// make one's return value as argument to another.
var compose = function (f, g) {
return function (x) {
return f(g(x));
}
}
// make sure a functions take a tuple and return a tuple.
var bind = function (f) {
return function (x) {
var a = x[0];
var b = x[1];
var c = f(a);
var y = c[0];
var w = c[1];
return [y, b + ' ' + w];
}
}
// for dealing with side effect.
// we can think the second value in container([x, '']) is a side effect,
// because sin and cube function has side effects, and we need to chain
// with such functions, so we have a monad that simulate sin and cube function.
// this function just accept one value and wrap it in a container.
var unit = function (x) {
return [x, '']
}
var lift = function (f) {
return function (x) {
return unit(f(x))
}
}
var input = 3;
// bind, unit
// var value = cube(sin(input));
// x -> y
var round = function (x) { return Math.round(x) }
// x -> (y, y)
// make it like sin function, so we can chain it together.
var roundLifted = lift(round);
// make args and return value symemetric.
// (x, x) -> (y, y)
var roundBinded = bind(roundLifted);
// compose sin and cube
var sinAndCube = compose(bind(cube), bind(sin));
// then compose with round.
var sinAndCubeAndRound = compose(sinAndCube, roundBinded);
var value = sinAndCubeAndRound(unit(input));
console.log(value);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment