// Copyright (c) 2013-2014 Quildreen Motta <quildreen@gmail.com> // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation files // (the "Software"), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. /** * Provides pure functional combinators. * * @module Core/Lambda */ // -- Aliases ---------------------------------------------------------- var toArray = Function.call.bind([].slice) // -- Implementation --------------------------------------------------- /** * The identity combinator. Always returns the argument it's given. * * @example * identity(3) // => 3 * identity([1]) // => [1] * * @summary a → a */ exports.identity = identity function identity(a) { return a } /** * The constant combinator. Always returns the first argument it's given. * * @example * constant(3)(2) // => 3 * constant('foo')([1]) // => 'foo' * * @summary a → b → a */ exports.constant = curry(2, constant) function constant(a, b) { return a } /** * Applies a function to an argument. * * @example * var inc = (a) => a + 1 * apply(inc)(3) // => 4 * * @summary (a → b) → a → b */ exports.apply = curry(2, apply) function apply(f, a) { return f(a) } /** * Inverts the order of the parameters of a binary function. * * @example * var subtract = (a) => (b) => a - b * subtract(3)(2) // => 1 * flip(subtract)(3)(2) // => -1 * * @summary (a → b → c) → (b → a → c) */ exports.flip = curry(3, flip) function flip(f, a, b) { return f(b)(a) } /** * Composes two functions together. * * @example * var inc = (a) => a + 1 * var square = (a) => a * a * compose(inc)(square)(2) // => 5, inc(square(2)) * * @summary (b → c) → (a → b) → (a → c) */ exports.compose = curry(3, compose) function compose(f, g, a) { return f(g(a)) } /** * Transforms any function on tuples into a curried function. * * @example * var sub3 = (a, b, c) => a - b - c * curry(3, sub3)(5)(2)(1) // => 2 * * @summary Number → ((a1, a2, ..., aN) → b) → (a1 → a2 → ... → aN → b) */ exports.curry = curry(2, curry) function curry(n, f) { return curried([]) function curried(args) { return function() { var newArgs = toArray(arguments) var allArgs = args.concat(newArgs) var argCount = allArgs.length return argCount < n? curried(allArgs) : argCount === n? f.apply(null, allArgs) : /* > n */ f.apply(null, allArgs.slice(0, n)) .apply(null, allArgs.slice(n)) }} } /** * Transforms a curried function into one accepting a list of arguments. * * @example * var add = (a) => (b) => a + b * spread(add)([3, 2]) // => 5 * * @summary (a1 → a2 → ... → aN → b) → (#[a1, a2, ..., aN) → b) */ exports.spread = curry(2, spread) function spread(f, as) { return as.reduce(function(g, a) { return g(a) }, f) } /** * Transforms a curried function into a function on tuples. * * @example * var add = (a) => (b) => a + b * uncurry(add)(3, 2) // => 5 * * @summary (a1 → a2 → ... → aN → b) → ((a1, a2, ..., aN) → b) */ exports.uncurry = uncurry function uncurry(f) { return function() { return spread(f, toArray(arguments)) } } /** * Applies an unary function to both arguments of a binary function. * * @example * var xss = [[1, 2], [3, 1], [-2, 4]] * sortBy(upon(compare, first)) * * @summary (b → b → c) → (a → b) → (a → a → c) */ exports.upon = curry(4, upon) function upon(f, g, a, b) { return f(g(a))(g(b)) }