UNPKG

fantasy-seqs

Version:

Homogenous array sequence data structure.

311 lines (300 loc) 7.5 kB
var daggy = require('daggy'), combinators = require('fantasy-combinators'), tuples = require('fantasy-tuples'), Option = require('fantasy-options'), constant = combinators.constant, identity = combinators.identity, Tuple2 = tuples.Tuple2, Seq = daggy.taggedSum({ Cons: ['cons'], Nil: [] }); // Methods Seq.of = function(x) { return Seq.Cons([x]); }; Seq.empty = function() { return Seq.Nil; }; Seq.prototype.chain = function(f) { return this.fold( Seq.Nil, function(a, b) { return a.concat(f(b)); } ); }; Seq.prototype.fold = function(v, f) { // TODO (Simon) : Trampoline this! var rec = function(a, index, b) { if (index < a.length) { return rec(a, index + 1, f(b, a[index])); } else return b; }; return this.cata({ Cons: function(x) { return rec(x, 0, v); }, Nil: constant(v) }); }; // Derived Seq.prototype.ap = function(a) { return this.chain(function(f) { return a.map(f); }); }; Seq.prototype.concat = function(x) { return x.fold(this, function(a, b) { return a.cata({ Cons: function(y) { return Seq.Cons(y.concat(b)); }, Nil: function() { return Seq.of(b); } }); }); }; Seq.prototype.map = function(f) { return this.chain(function(x) { return Seq.of(f(x)); }); }; Seq.prototype.reverse = function() { return this.cata({ Cons: function(y) { return Seq.Cons(y.slice().reverse()); }, Nil: Seq.empty }); }; // Common Seq.prototype.filter = function(f) { return this.cata({ Cons: function(x) { var accum = [], i; for (i = 0; i < x.length; i++) { if (f(x[i])) accum.push(x[i]); } return Seq.Cons(accum); }, Nil: Seq.empty }); }; Seq.prototype.find = function(f) { return this.cata({ Cons: function(x) { var i; for(i = 0; i < x.length; i++) { if (f(x[i])) { return Option.of(x[i]); } } return Option.None; }, Nil: function() { return Option.None; } }); }; Seq.prototype.first = function() { return this.cata({ Cons: function(x) { return Option.of(x.slice(0, 1)[0]); }, Nil: function() { return Option.None; } }); }; Seq.prototype.init = function() { return this.cata({ Cons: function(x) { return Seq.Cons(x.slice(1)); }, Nil: Seq.empty }); }; Seq.prototype.last = function() { return this.cata({ Cons: function(x) { return Option.of(x[x.length - 1]); }, Nil: function() { return Option.None; } }); }; Seq.prototype.partition = function(f) { return this.cata({ Cons: function(x) { var lhs = [], rhs = [], i; for (i = 0; i < x.length; i++) { if (f(x[i])) lhs.push(x[i]); else rhs.push(x[i]); } return Tuple2(Seq.Cons(lhs), Seq.Cons(rhs)); }, Nil: function() { return Tuple2(Seq.Nil, Seq.Nil); } }); }; Seq.prototype.reduce = function(f) { // TODO (Simon) : Trampoline this! var rec = function(a, index, b) { if (index < a.length) { return rec(a, index + 1, f(b, a[index])); } else return b; }; return this.cata({ Cons: function(x) { return rec(x, 1, x[0]); }, Nil: constant(null) }); }; Seq.prototype.take = function(x) { var env = this; return this.cata({ Cons: function(x) { return Seq.Cons(x.slice(0, x)); }, Nil: constant(env) }); }; Seq.prototype.zip = function(x) { return this.cata({ Cons: function(a) { return x.cata({ Cons: function(b) { var i = 0, accum = [], numOf = Math.min(a.length, b.length); for (i = 0; i < numOf; i++) { accum.push(Tuple2(a[i], b[i])); } return Seq.Cons(accum); }, Nil: Seq.empty }); }, Nil: Seq.empty }); }; // IO Seq.from = function(a, b) { var i = 0, accum = []; for (i = a; i < b; i++) { accum.push(i); } return Seq.fromArray(accum); }; Seq.fromArray = function(a) { return a.length < 1 ? Seq.Nil : Seq.Cons(a); }; Seq.prototype.toArray = function() { return this.cata({ Cons: identity, Nil: constant([]) }); }; // Transformer Seq.SeqT = function(M) { var SeqT = daggy.tagged('run'), sequence = function(x) { return x.fold(M.of(Seq.empty()), function(a, b) { return a.chain(function(x) { return b.chain(function(y) { return M.of(x.concat(y)); }); }); }); }; SeqT.of = function(x) { return SeqT(M.of(Seq.of(x))); }; SeqT.empty = function() { return SeqT(M.of(Seq.empty())); }; SeqT.prototype.fold = function(a, b) { return this.run.chain(function(o) { return M.of(o.fold(a, b)); }); }; SeqT.prototype.chain = function(f) { var m = this.run; return SeqT(m.chain(function(o) { return sequence( o.fold(Seq.empty(), function(a, b) { return a.concat(Seq.of(f(b).run)); }) ); })); }; SeqT.prototype.concat = function(x) { return SeqT(sequence( Seq.of(this.run).concat(Seq.of(x.run)) )); }; SeqT.prototype.map = function(f) { return this.chain(function(a) { return SeqT.of(f(a)); }); }; SeqT.prototype.ap = function(a) { return this.chain(function(f) { return a.map(f); }); }; SeqT.prototype.reverse = function() { var m = this.run; return SeqT(m.map(function(x){ return x.reverse(); })); }; // Common SeqT.prototype.filter = function(f) { var m = this.run; return SeqT(m.map(function(x) { return x.filter(f); })); }; SeqT.prototype.partition = function(f) { var m = this.run; return SeqT(m.map(function(x) { return x.partition(f); })); }; SeqT.prototype.take = function(n) { var m = this.run; return SeqT(m.map(function(x) { return x.take(n); })); }; SeqT.prototype.zip = function(x) { var m = this.run, n = x.run; return SeqT(m.chain(function(x) { return n.map(function(y) { return x.zip(y); }); })); }; // IO SeqT.fromSeq = function(x) { return SeqT(M.of(x)); }; SeqT.fromArray = function(x) { return SeqT(M.of(Seq.fromArray(x))); }; return SeqT; }; // Export if(typeof module != 'undefined') module.exports = Seq;