Partial application right to left? - javascript

When using bind in JS, one can create functions with predefined arguments, e. g.:
var add = function (a, b) {
return a + b;
};
var addToThree = add.bind(null, 3);
But how to I do this if I want to predefine the second, third etc. argument, but not the first?

In ES2015 you can do something like this:
const partial = fn => (...pargs) => (...args) => fn.apply(null, [...pargs, ...args]);
const partialRight = fn => (...pargs) => (...args) => fn.apply(null, [...args, ...pargs.reverse()]);
const myFunc = (one, two, three, four) => {
console.log(one);
console.log(two);
console.log(three);
console.log(four);
};
const myFuncPartial = partial(myFunc)('1');
const myFuncPartialRight = partialRight(myFuncPartial)('4', '3');
myFuncPartialRight('2');

You can do
var add = function (a, b) {
b = b || 5;
return a + b;
};
In ES6 Default Parameters can be used in a very easy way
var add = function (a, b=5) {
return a + b;
};
and call it like add(3);

Related

How to create a composition from functions

I have 5 functions: func1(), func2(), func3(), func4(), func5(). I need to implement the compositionFunc() function, which can take any number of functions as arguments, and create a composition from them. The compositionFunc() function takes my 5 functions as arguments. The compositionFunc() function returns a function that takes its initial value as an argument. This nested function successively passing through an array of functions with each iteration returns the result of calling the accumulated value of the current function-argument. The result of one function can be passed as an argument to another function. How can i do this?
const func1 = (arg1) => {
return arg1;
};
const func2 = (arg2) => {
return arg2;
};
const func3 = (arg3) => {
return arg3;
};
const func4 = (arg4) => {
return arg4;
};
const func5 = (arg5) => {
return arg5;
};
const compositionFunc = () => {
...
};
you can define a function like this
const pipe = (...functions) => args => functions.reduce((res, f) => f(res), args)
const combine = (...functions) => args => functions.reduceRight((res, f) => f(res), args)
const plus1 = x => x + 1
const double = x => x * 2
const pipeFunction = pipe(plus1, double)
const combineFunction = combine(plus1, double)
console.log(combineFunction(1)) // (1 * 2) + 1
console.log(pipeFunction(1)) // (1 + 1) * 2
A simple reduce can accomplish that:
function pipe(input, ...func) {
return func.reduce((a, f) => f(a), input);
}
You pass it an initial value + chain of functions.
Example:
function f1(val) {
return val + 1;
}
function f2(val) {
return val * 10;
}
console.log(pipe(2, f1, f2)); //=> 30

How to execute one function whether it normal or carried and yield the same result?

What would be the body of a the multiply function that if executed in both ways below would give the same result. So either calling multiply(2,4) or multiply(2)(4) would output 8?
You can check if second arg is passed or not.
function multiply(a,b){
if(b === undefined){
return function(b){
return a * b;
}
}
return a * b
}
console.log(multiply(2,4))
console.log(multiply(2)(4))
const multiply = (a,b) => !b ? (b) => a * b : a * b;
console.log(multiply(2, 4))
console.log(multiply(2)(4))
Fairly simple - check if the second argument exists, and modify the return value accordingly:
const multiply = (a, b) => b ? a * b : c => a * c;
console.log(multiply(2, 3));
console.log(multiply(2)(4));
This can also be extended fairly simply to take three arguments:
const multiply = (a, b, c) => c ? a * b * c : (b ? (d => a * b * d) : (d, e) => a ? d * e : f => d * f);
console.log(multiply(2, 3, 4));
console.log(multiply(2, 5)(3));
console.log(multiply(2)(6, 3));
Whenever you have a curied function, you need some way to end the currying, just as you need a base case for recursion. That end condition can either be
(1) the number of arguments, e.g. 2 in this case:
const curry = (fn, n) => {
const c = (...args) => (...args2) => args.length + args.length >= n ? fn(...args, ...args2) : c(...args, ...args2);
return c();
};
const add = curry((a, b) => a + b, 2);
(1b) For sure that can also be derived from the functions signature:
const curry = (fn, ...keep) => (...args) => keep.length + args.length >= fn.length ? fn(...keep, ...args) : curry(fn, ...keep, ...args);
const add = curry((a, b) => a + b);
(2) a final empty function call e.g. add(1, 2)() or add(1)(2)()
const curry = fn => (...args) => (...args2) => args2.length ? curry(fn)(...args, ...args2) : fn(...args, ...args2);
const add = curry((a, b) => a + b);
(3) some typecast at the end, to trigger the result to be calculated, e.g. +add(1, 2) or +add(1)(2):
const curry = (fn, ...keep) => {
const c = (...args) => curry(fn, ...keep, ...args);
c.valueOf = () => fn(...keep);
return c;
};
const add = curry((a, b) => a + b);

Execute Multiple functions in a function

function executeActions(param)
{
if((param != undefined) && (param.length > 0))
{
for(i=0; i < param.length; i++)
{
//eval like function
param[i]();
}
}
}
function clearFields()
{
...
}
function showAbs(param)
{
if(param == 'insert')
{
...
}
else if(param == 'update')
{
...
}
else
{
...
}
}
$("#clearButton").click(function(event)
{
//var functions = ["clearFields()","showAbs('insert')"];
var a = showAbs('insert');
var functions = [clearFields, a];
executeActions(functions);
});
Hello everyone!
How can I execute some functions with parameters in a row in a set of instructions like i've showed above?
If they don't have any parameters, then the functions execute like in chain, but, if one or more of them uses
some parameters, it stops with the error: "param[i] is not a function".
Maybe if you have another elegant solution for this code, i'd appreciate if you share with us.
Thank you all in advance!
You can use partial application for this. Partial application means that you take a given function and fix one or more parameters to it. Example
function sum(a, b){
return a + b;
}
function product(a, b){
return a * b;
}
function doSomething(){
// do something
}
function runFunctions(funcs){
for(var i = 0;i<funcs.length;i++){
funcs[i]();
}
}
var mySum = function(){
return sum(5, 6);
}
var myProduct = function(){
return product(2, 3);
}
runFunctions(mySum, myProduct, doSomething);
The above is using ES 5 syntax. You could make this a bit more concise using ES 6 syntax:
const sum = (a, b) => a + b;
const product = (a, b) => a * b;
const doSomething = () => // do something
const runFunctions = funcs => {
for(func of funcs)
func();
}
var mySum = () => sum(5, 6);
var myProduct = () => product(2, 3);
runFunctions(mySum, myProduct, doSomething);
or you could use the bind function to take care of fixing the vars:
const sum = (a, b) => a + b;
const product = (a, b) => a * b;
const doSomething = () => // do something
const runFunctions = funcs => {
for(func of funcs)
func();
}
runFunctions(sum.bind(null, 5,6), myProduct.bind(null, 2,3), doSomething);
For me a way you want to achieve may be not readable for other developers.
You may create a function that will group all your function executions like:
function groupedFunctions{
return {
A: funcA(param),
B: funcB(param),
C: funcC(param)
}
}
function executeActions(funcObj, params) {
funcObj.A(params.a);
funcObj.B(params.b);
}
let params = {a: 1, b:2}
executeActions(groupedFunction(), params)

How to call this default args function more than once?

I have encountered a question where I need to allow default args to be set on a function in JavaScript:
function dfltArgs(func, params) {
const strFn = func.toString()
console.log(strFn)
const args = /\(([^)]+)\)/.exec(strFn)[1].split(',')
const defaultVal = (arg, val) => typeof arg !== 'undefined' ? arg : val
return (...dynamicArgs) => {
const withDefaults = args.map((arg, i) =>
defaultVal(dynamicArgs[i], params[args[i]]))
return func(...withDefaults)
}
}
function add (a, b) { return a + b }
var add_ = dfltArgs(add,{b:9})
console.log(add_(10)) // Should be 19
var add_ = dfltArgs(add_,{b:3})
console.log(add_(10)) // Should now be 13
However, I need to be able to call this function more than once and overwrite previously set defaults:
var add_ = defaults(add,{b:9})
add_(10) // Should be 19
var add_ = defaultArguments(add_,{b:3})
add_(10) // Should now be 13
This does not work in my implementation, because the stringified function on the second call is: (...dynamicArgs) => {, etc.
How can I refactor this? Probably need to use bind somehow?
Instead of your complicated default args thing, why not just use some arrow functions with real default arguments:
var _add = (a, b = 8) => add(a, b);
That way you can easily change the bound things:
var add_ = (a = 2, b) => _add(a, b);
add_() // 10

passing argument to map function

I have code like:
var addX = (e) => return e+1;
I am calling like:
[1,2,3].map(addX);
Can I make "1" dynamic? Like:
[1,2,3].map(addX(2)); //this wont work, in this case it should add 2
You need a closure over e and return a function with one parameter for the callback.
var addX = x => v => x + v;
console.log([1, 2, 3].map(addX(2)));
You can use currying like this:
var addX = n => e => e + n;
console.log([1,2,3].map(addX(2)));
console.log([1,2,3].map(addX(10)));
What this does is, you pass the number (n) that you want to be added to the function and it returns a new function which adds that number to it's argument (e) (each element when using map)
You can use bind(thisArg, argument1) to send an extra parameter
var addX = (a, b) => a+b;
console.log("2", [1,2,3].map(addX.bind(Array, 2)))
console.log("5", [1,2,3].map(addX.bind(Array, 5)))
The this argument really does not matter in this case. I just put Array there, it can be this, null, etc.
You can create a function to return a function that takes your add amount.
Here is an example below.
var addX = (addbit) => (e) => e + addbit;
console.log([1,2,3].map(addX(2)));
I would do something like this :)
var addX = (e) => e+1;
[1,2,3].map(num => addX(num))
Several utility libraries like Lodash, Underscore, and Ramda provide a curry() utility function that takes a function and returns a new version of that function that can take the same arguments one at a time, a few at a time, or all at once.
This means that you can create an add function that can either add two numbers right away add(4, 5) or that can "pre-bake" a function with one of the values included: const increment = add(1); console.log(increment(5));
const add = _.curry((x, y) => x + y);
console.log(add(6, 7));
console.log([1,2,3].map(add(10)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
If you don't want to include a whole library just for this purpose, you can also use this standalone version of curry:
var curryN = (function () {
var slice = Function.prototype.call.bind(Array.prototype.slice);
var bindArr = function (f, arr) { return f.bind.apply(f, [{}].concat(arr)); };
return function curryN(argCount, func) {
return function fn() {
var args = slice(arguments, 0, argCount);
return args.length === argCount
? func.apply({}, args)
: bindArr(fn, args);
};
};
})();
var curry = function curry(func) { return curryN(func.length, func); };
const add = curry((x, y) => x + y);
console.log(add(6, 7));
console.log([1,2,3].map(add(10)));
You can use closure for that:
var addX = inc => e => e + inc;
var res = [1,2,3].map(addX(2));
console.log(res);
EXPLANATION
var addX = inc => e => e + inc;
Is the equivalent of:
var addX = function(inc) {
return function(e) {
return e + inc;
}
}
So addX(2) returns the callback function(e) { return e + 2 } and it's the callback used by array.map

Categories