Skip to content

Instantly share code, notes, and snippets.

@gerardpaapu
Last active August 7, 2017 23:51
Show Gist options
  • Save gerardpaapu/9224895 to your computer and use it in GitHub Desktop.
Save gerardpaapu/9224895 to your computer and use it in GitHub Desktop.
Async IO Monad for Javascript
var body = forever $do {
a <- readN(6)
b <- read1
write([a, b])
};
performWith(ls)(body);
// a sweet.js macro for a subset of haskell style do-notation
macro $do {
rule { { $y:expr } } => {
$y
}
rule { { $x:ident <- $y:expr $rest ... } } => {
($y.chain(function($x) {
return $do { $rest ... }
}));
}
}
function IO(unsafePerform) {
this.unsafePerform = unsafePerform;
}
IO.prototype.of = IO.of = function (v) {
return new IO(function (ctx, cb) {
cb(null, v);
});
};
IO.prototype.empty = IO.empty = function () {
return IO.fail(null);
};
IO.fail = function (message) {
return new IO(function (ctx, cb) {
cb(new Error(message));
});
};
IO.prototype.handleError = function (f) {
var io = this;
return new IO(function (ctx, cb) {
io.unsafePerform(ctx, function (err, v) {
if (err != null) { f(err, cb); }
else { cb(null, v); }
});
});
};
IO.prototype.chain = function (f) {
var io = this;
return new IO(function (ctx, cb) {
io.unsafePerform(ctx, function (e, v) {
if (e != null) {
cb(e);
} else {
f(v).unsafePerform(ctx, cb);
}
});
});
};
IO.prototype.map = function (f) {
return this.chain(function (v) {
return IO.of(f(v));
});
};
IO.prototype.ap = function (io) {
return this.chain(function (f) {
return io.map(f);
});
};
function write() {
var args = arguments;
return new IO(function (stream, cb) {
stream.write(args);
cb(null, null);
});
}
var read1 = new IO(function (stream, cb) {
stream.read(cb);
});
function liftM2(f) {
return function (a, b) {
return a.chain(function (x) {
return b.map(function (y) {
return f(x, y);
});
});
};
}
var cons = liftM2(function (a, b) {
return [a].concat(b);
});
function readN(n) {
return n === 0 ? IO.of([])
: cons(read1, readN(n - 1));
}
function perform(ls) {
return function (io) {
io.unsafePerform(ls, function (e, v) {
if (e != null) {
throw e;
}
});
};
}
function forever(f) {
return $do {
_ <- f()
forever(f)
};
}
write: [ [ 0, 1, 2, 3, 4, 5 ], 6 ]
write: [ [ 7, 8, 9, 10, 11, 12 ], 13 ]
write: [ [ 14, 15, 16, 17, 18, 19 ], 20 ]
write: [ [ 21, 22, 23, 24, 25, 26 ], 27 ]
write: [ [ 28, 29, 30, 31, 32, 33 ], 34 ]
write: [ [ 35, 36, 37, 38, 39, 40 ], 41 ]
write: [ [ 42, 43, 44, 45, 46, 47 ], 48 ]
write: [ [ 49, 50, 51, 52, 53, 54 ], 55 ]
write: [ [ 56, 57, 58, 59, 60, 61 ], 62 ]
write: [ [ 63, 64, 65, 66, 67, 68 ], 69 ]
write: [ [ 70, 71, 72, 73, 74, 75 ], 76 ]
write: [ [ 77, 78, 79, 80, 81, 82 ], 83 ]
write: [ [ 84, 85, 86, 87, 88, 89 ], 90 ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment