uncurry.js (3278B)
1 /** 2 * @license Apache-2.0 3 * 4 * Copyright (c) 2018 The Stdlib Authors. 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 'use strict'; 20 21 // MODULES // 22 23 var isFunction = require( '@stdlib/assert/is-function' ); 24 var isPositiveInteger = require( '@stdlib/assert/is-positive-integer' ).isPrimitive; 25 26 27 // MAIN // 28 29 /** 30 * Transforms a curried function into a function invoked with multiple arguments. 31 * 32 * @param {Function} fcn - curried function 33 * @param {PositiveInteger} [arity] - number of parameters 34 * @param {*} [thisArg] - evaluation context 35 * @throws {TypeError} first argument must be a function 36 * @throws {TypeError} `arity` argument must be a positive integer 37 * @returns {Function} uncurried function 38 * 39 * @example 40 * function addX( x ) { 41 * return function addY( y ) { 42 * return x + y; 43 * }; 44 * } 45 * 46 * var add = uncurry( addX ); 47 * 48 * var sum = add( 2, 3 ); 49 * // returns 5 50 */ 51 function uncurry( fcn, arity, thisArg ) { 52 var context; 53 var len; 54 if ( !isFunction( fcn ) ) { 55 throw new TypeError( 'invalid argument. First argument must be a function. Value: `'+fcn+'`.' ); 56 } 57 if ( arguments.length < 2 ) { 58 len = null; 59 } 60 else if ( arguments.length > 2 ) { 61 len = arity; 62 context = thisArg; 63 if ( !isPositiveInteger( len ) ) { 64 throw new TypeError( 'invalid argument. Arity argument must be a positive integer. Value: `'+len+'`.' ); 65 } 66 } 67 else if ( isPositiveInteger( arity ) ) { 68 len = arity; 69 } 70 else { 71 len = null; 72 context = arity; 73 } 74 return uncurried; 75 76 /** 77 * Uncurried function. 78 * 79 * @private 80 * @param {...*} args - arguments 81 * @throws {Error} if arity is set, must provide expected number of input arguments 82 * @throws {Error} configured arity must be compatible with curried function 83 * @throws {Error} if arity is not set, number of arguments must be compatible with curried function 84 * @returns {*} function result 85 */ 86 function uncurried() { 87 var f; 88 var i; 89 90 f = fcn; 91 if ( len ) { 92 if ( len > arguments.length ) { 93 throw new Error( 'insufficient input arguments. Expected '+len+' argument(s) and only received '+arguments.length+' argument(s).' ); 94 } 95 for ( i = 0; i < len; i++ ) { 96 if ( isFunction( f ) ) { 97 f = f.call( context, arguments[ i ] ); 98 } else { 99 throw new Error( 'invalid invocation. The configured arity exceeds the number of possible curried function invocations. Expected: '+len+'. Actual: '+i+'.' ); 100 } 101 } 102 return f; 103 } 104 for ( i = 0; i < arguments.length; i++ ) { 105 if ( isFunction( f ) ) { 106 f = f.call( context, arguments[ i ] ); 107 } else { 108 throw new Error( 'invalid invocation. Number of arguments exceeds the number of possible curried function invocations. Expected: '+arguments.length+'. Actual: '+i+'.' ); 109 } 110 } 111 return f; 112 } 113 } 114 115 116 // EXPORTS // 117 118 module.exports = uncurry;