@fpjs/overture
Version:
A Javascript prelude
63 lines (55 loc) • 2.11 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
/**
* Callback wraps a Node.js-style callback function to provide functor,
* applicative and monadic operations on it.
*
* Like all callback-style functions, it short-circuits computation upon the
* first error.
*/
import {rapply, type} from "@fpjs/overture/base";
import {map} from "@fpjs/overture/algebras/functor";
/** Build a continuation on a callback function. */
///:: ((e, a) -> ()) -> (a -> ((e, b) -> ())) -> ((e, b) -> ()) -> ()
const mkcont = (cb) => (f) => (done) =>
cb((err, x) => (err != null) ? done(err) : f(x)(done));
///:: ((e, a) -> ()) -> Callback e a
export const Callback = (cb) => ({
'@@type': 'Callback',
'constructor': Callback,
'_callback': cb,
'fantasy-land/map': (f) => Callback(
mkcont (cb) ((x) => (done) => done (null, f (x)))
),
'fantasy-land/ap': (ab) => Callback(
mkcont (cb) ((x) => (map (rapply (x)) (ab))['_callback'])
),
'fantasy-land/chain': (f) => Callback(
mkcont (cb) ((x) => f(x)['_callback'])
),
});
Callback['fantasy-land/of'] = (x) => Callback((done) => done(null, x));
/** Run a Callback and process it's result with a callback-style function. */
///:: ((e, a) -> ()) -> Callback e a -> ()
export const runCallback = (f) => (o) => {
const op = o['_callback'];
if (op === undefined) {
throw TypeError(`${type(o)} is not Callback`);
}
return op (f);
};
/** Constructor for a Callback with an error. */
///:: (e) => Callback e a
export const error = (e) => Callback ((done) => done(e));
/** Recover from specific errors. */
///:: (e -> Callback e a) -> Callback e a -> Callback e a
export const recover = (f) => (o) => {
const cb = o['_callback'];
if (cb === undefined) {
throw TypeError(`${type(o)} is not Callback`);
}
return Callback ((done) => cb (
(e, r) => e === null ? done(null, r) : (runCallback (done) (f (e)))
));
};