/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Mozilla Boost library project. * * The Initial Developer of the Original Code is 8x8 Inc. * Portions created by the Initial Developer are Copyright (C) 2005 * the Initial Developer. All Rights Reserved. * * Contributor(s): * david Marteau (original author) * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ EXPORTED_SYMBOLS = [ "Functional" ]; /** * Functional * * */ const Functional = { /* * Utilities */ bind: function Functional_bind( f, obj ) { return function() f.apply(obj, arguments); }, slice_args: function Functional_slice_args(a, /*[opt]*/ i) { return Array.prototype.slice.call(a, i); }, /** * Returns a function that takes an object as an argument and applies 'method' * to argument sequence */ invoke: function Functional_invoke( method ) { return function( obj, seq ) obj[method].apply(obj,seq && Functional.expand(seq)); }, /** * Returns a function that takes an object, * and returns the value of its 'name' property */ pluck: function Functional_pluck( name ) { return function( obj ) obj[name]; }, /* * Generators returning a sequence */ /** * Return a sequence from its argument list */ seq: function Functional_sequence( /* a1,a2,...,an */ ) { for(let n = arguments.length,i=0;i=0;) yield arguments[i]; }, /** * Create an empty sequence */ empty: function Functional_empty() { return new Iterator({}); }, /** * Cons an object onto a sequence. * * cons(x,(a1,...,an)) -> (x,a1,...,an) */ cons: function Functional_cons( obj, seq ) { yield obj; for(let x in seq) yield x; }, /** * Car of a sequence */ car: function Functional_car( seq ) { try { return seq.next(); } catch(err if err instanceof StopIteration) {} return null; }, /** * Cdr of a sequence. */ cdr: function Functional_cdr( seq ) { try { return (seq.next(),seq); } catch(err if err instanceof StopIteration) {} return null; }, /** * setcar */ setcar: function Functional_setcar( seq, obj ) { seq.next(); yield obj; for(let x in seq) yield x; }, /** * setcdr */ setcdr: function Functional_setcdr( seq1, seq2 ) { try { yield seq1.next(); } catch(err if err instanceof StopIteration) {} for(let x in seq2) yield x; }, /** * range */ range: function Functional_range( begin, end ) { for (let i = begin; i < end; ++i) { yield i; } }, /** * concat */ concat: function Functional_concat( /* seq1, seq2, ..., seqn */ ) { for(let seq in Functional.seq.apply(null,arguments)) { for(let x in seq) yield x; } }, /* * High order generators */ /** * map(f, [x1, x2…]) = [f(x1), f(x2), …] * * Applies fn to each element of sequence. */ map: function Functional_map( f, seq ) { for(let x in seq) yield f(x); }, /** * reduce(f, init, [x0, x1, x2]) =def f(f(f(init, x0), x1), x2) * * Applies fn to init and the first element of sequence, * and then to the result and the second element, and so on. */ reduce: function Functional_reduce( f, init, seq ) { let u = init; for(let x in seq) { u = f(u,x); yield u; } }, /** * Returns a list of those elements x of sequence * such that f(x) returns true. */ filter: function Functional_filter( f, seq ) { for(let x in seq) if(f(x)) yield x; }, /* * Partial function application * * curry,rcurry,saturate * args is an array of arguments passed to the inner function */ /** * curry creates a new function that applies the original arguments, and * then the new arguments: */ curry: function Functional_lcurry( f , args ) { return function(/* arguments */) f.apply(null,args.concat(Functional.slice_args(arguments))); }, /** * rcurry (right curry) creates a new function that applies the new arguments, and * then the original arguments: */ rcurry: function Functional_rcurry( f , args ) { return function(/* arguments */) f.apply(null,Functional.slice_args(arguments).concat(args)); }, /** * Return a function that 'saturate' all arguments of f * with this arguments list (i.e bind f with the passed arguments) */ saturate: function Functional_saturate( f, args ) { return function() f.apply(null,args); }, /** * define a constante function */ defconst: function Functional_fconst( value ) { return function() value; }, /* * Combinators */ /** * compose(f1, f2, f3…, fn)(args) =def f1(f2(f3(…(fn(args…))))) */ compose: function Functional_compose( /* f1,f2,...,fn */ ) { let args = Functional.reversed_seq.apply(null,arguments); return (function() { let x = Functional.car(args).apply(null,arguments); for(let fn in args) { x = fn(x); } return x; }); }, /* * Evaluators: these functions evaluate a sequence and return * a value */ /** * Expand a sequence to an array */ expand: function Functional_expand( seq ) { return [x for(x in seq)]; }, /** * Apply the first element of seq to the remaining * elements */ apply: function Functional_apply( seq, obj ) { with(Functional) return car(seq).apply(obj,expand(seq)); }, /** * Evaluate all element in sequence, return the last value. */ evaluate: function Functional_evaluate( seq ) { for(var x in seq) {} return x; }, /* * Predicates (note that predicates are also evaluators) */ /** * Returns true when at least one element of the sequence is true */ some: function Functional_some( seq ) { for(let x in seq) { if(x) return true; } return false; }, /** * Returns true when every element of the sequence are true */ every: function Functional_every( seq ) { for(let x in seq) { if(!x) return false; } return true; } };