UNPKG

green_curry

Version:
263 lines (207 loc) 5.5 kB
var hack = arr => function () { arr.push (this) return 0 } const F = module.exports = { ///////////// // // // Basic // // // ///////////// // 'a -> 'a id: x => x, // 'a -> unit -> 'a const: x => () => x, // 'a -> unit ignore: () => undefined, // (unit -> 'a) -> 'a exec: f => f (), // bool -> unit throw: x => {throw x}, // 'a -> unit log: console.log.bind (console), // 'a -> string array -> int -> unit log_json: x => r => i => console.log (JSON.stringify (x, r, i)), // string -> 'a // wrapper for eval required // operates at global scope (ie: ignores variables) if pointless form eval: x => eval (x), '=': x => y => { if (x === y) { return true } else if (typeof x === 'object' && typeof y === 'object') { if (Array.isArray (x) !== Array.isArray (y)) { return false } else if (Array.isArray (x) && Array.isArray (y)) { if (x.length !== y.length) { return false } for (let i = 0; i < x.length; i++) { if (! F['='] (x[i]) (y[i])) { return false } } return true } else { const kx = Object.keys (x) const ky = Object.keys (y) if (kx.length !== ky.length) { return false } for (let i = 0; i < kx.length; i++) { if (! F['='] (x[kx[i]]) (y[kx[i]])) { return false } } return true } } else { return false } }, '==': x => y => x == y, '===': x => y => x === y, '!=': x => y => x != y, '<>': x => y => x != y, '!==': x => y => x !== y, '>': x => y => x > y, '>=': x => y => x >= y, '<': x => y => x < y, '<=': x => y => x <= y, '!': x => ! x, '~': x => ~ x, '+': x => y => x + y, '-': x => y => x - y, '*': x => y => x * y, '/': x => y => x / y, '%': x => y => x % y, '|': x => y => x | y, '||': x => y => x || y, '&': x => y => x & y, '&&': x => y => x && y, '^': x => y => x ^ y, '>>>': x => y => x >> y, '>>>>': x => y => x >>> y, '<<<': x => y => x << y, '??': x => y => ! [undefined, null].includes (x) ? x : y, '?:': x => y => z => x ? y : z, '|>': x => f => f (x), '@@': x => f => f (x), '<|': f => x => f (x), '>>': f => g => x => g (f (x)), '<<': f => g => x => f (g (x)), ///////////////// // // // Functions // // // ///////////////// // ('a -> bool) -> ('a -> bool) neg: f => x => ! f (x), // ('a -> bool) -> ('a -> bool) -> ('a -> bool) union: f => g => x => f (x) || g (x), // ('a -> bool) -> ('a -> bool) -> ('a -> bool) inter: f => g => x => f (x) && g (x), try: f => { return { catch: g => { try { return f () } catch (err) { return g (err) } } } }, // (a' -> 'b -> 'c) -> 'b -> 'a -> 'c swap: f => x => y => f (y) (x), // int -> ('a -> 'b) -> unit delay: t => f => setTimeout (f, t), // ('a -> 'b) -> 'a -> 'a tap: f => x => (f (x), x), // note: all composition functions here are reverse composition // if JavaScript had operator overloading, i'd happily // use that and type it properly as // ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c // but without an infix operator, it'd be verbose non-variadic // (? -> ?) array -> (? -> ?) rcomp: fs => x => fs.reduce ((a, h) => h (a), x), // alternatively this operator overloading hack that i lifted from: // http://scott.sauyet.com/Javascript/Talk/Compose/2013-05-22/#slide-33 c: () => { const fs = [] const valueOf = Function.prototype.valueOf Function.prototype.valueOf = hack (fs) return f => { Function.prototype.valueOf = valueOf return F.rcomp (fs.length ? fs : [f || F.id]) } }, // adaptation of above that pipes a given argument through the composed function p: x => { const fs = [] const valueOf = Function.prototype.valueOf Function.prototype.valueOf = hack (fs) return f => { Function.prototype.valueOf = valueOf return F.rcomp (fs.length ? fs : [f || F.id]) (x) } }, // ('a -> 'b) -> ('a -> 'b) memoize: f => { const memo = [] return x => { const len = memo.length for (var i = 0; i < len; i++) if (memo [i] [0] === x) return memo [i] [1] memo [len] = [x, f (x)] return memo [len] [1] } }, // int -> (unit -> unit) -> unit times: x => f => {for (var n = 0; n < x; n++) f ()}, // int -> ('a -> 'b') -> ('a -> unit/'b) after: n => f => x => n-- >= 1 ? undefined : f (x), // int -> ('a -> 'b') -> ('a -> unit/'b) before: n => f => x => n-- >= 1 ? f (x) : undefined, match: x => { const cases = [] const o = { case: p => f => { cases.push ([p, f]) return o }, default: f => ((cases.find (y => y [0] === x) || []) [1] || f) (x), end: f => ((A.find (y => y [0] === x) (cases) || []) [1] || f) (x), } return o }, match_f: x => { const cases = [] const o = { case: p => f => { cases.push ([p, f]) return o }, default: f => ((cases.find (y => y [0] (x)) || []) [1] || f) (x), } return o }, P: { try: f => ({ catch: async g => { try { return await f () } catch (err) { return await g (err) } } }), }, }