I would like to know if it possible to find out how many remaining arguments a curried function is expecting in javascript, if possible, without ever actually calling the function.
I want a function that takes a function and returns if the function is expecting 2 or more remaining arguments.
hasSeveralRemainingArguments: fn => bool
Let's say I have the functions:
const double = x => 2*x;
const inc = x => x + 1;
const divideBy = ({dividor}) => x => x/dividor;
const decrementAndDivideBy = ({dividor}) => x => (x - 1)/dividor;
hasSeveralRemainingArguments(double); // false
hasSeveralRemainingArguments(inc); // false
hasSeveralRemainingArguments(divideBy); // true
hasSeveralRemainingArguments(divideBy({dividor: 5})); // false
hasSeveralRemainingArguments(decrementAndDivideBy); // true
hasSeveralRemainingArguments(decrementAndDivideBy({dividor: 5})); // false
The usecase would be a function foo which expects an options argument and an array of functions to call. I want to "pipe" through the array of functions and input the options argument only to the functions that are actually expecting the argument like in this case divideBy and decrementAndDivideBy, e.g.:
const pipe = (...fns) => x => fns.reduce((y, fn) => fn(y), x);
const foo = (options = {}) => (fns = []) => pipe(
fns.map(fn => (
hasSeveralRemainingArguments(fn) ?
fn(options) :
fn
)
);
const bar = (...fns) => {
const options = {
dividor: 3
}; // local, not known to the caller of bar. They just know that they can pass in a function which will receive an options-object, they just don't know what is inside this object.
return foo(options)(fns);
});
const baz = bar(
double,
inc,
divideBy,
decrementAndDivideBy
);
baz(4); // ((4*2 + 1)/3 - 1)/3 = 0.67
baz(10); // ((10*2 + 1)/3 - 1)/3 = 2
The options argument is not known by the caller of the function bar. Otherwise I could input the options argument before passing the functions into bar but this is unfortunately not possible.
You should also note that double, inc, divideBy and decrementAndDivideBy are built to only accept numbers as the argument x but this might not always be the case. If possible, I don't want to call the functions and test if the returned value is a function or not but currently I do not see any other way.
I could also pass objects with a function and a boolean "isExpectingOptions" but this would not be very nice/elegant for the person calling bar.
Do you have another idea?
Have you considered using the length property of a function?
The length property indicates the number of parameters expected by the function.
const a = curry((x, y, z) => 42);
a.length // 3
a(1).length // 2
a(1)(2).length // 1
As pointed out already,
you can check the arity of the function,
however this doesn't really work if currying is achieved manually.
const nSum = R.curry((a, b, c) => {
console.log('nSum.length', nSum.length);
return a + b + c;
});
const uSum = (a) => (b) => (c) => {
console.log('uSum.length', uSum.length);
return a + b + c;
};
nSum(1, 2, 3);
uSum(1)(2)(3);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.0/ramda.js" integrity="sha256-buL0byPvI/XRDFscnSc/e0q+sLA65O9y+rbF+0O/4FE=" crossorigin="anonymous"></script>
You could potentially build a getArity function,
but this would require applying the function to extract the number of its arguments...
const getArity = (fn, arg) => {
const res = fn(arg);
return 1 + (
typeof res === 'function' ? getArity(res, arg) : 0
);
};
const uSum = (a) => (b) => (c) => a + b + c;
console.log(
getArity(uSum, 0),
);
const sum2 = uSum(0);
console.log(
getArity(sum2, 0),
);
This function, also, doesn't really tell you the arity of the function...
but how many time can be curried if we assume it as unary.
Related
I'm trying to create a currying function returning the list of parameters but I don't how to make it.
This is my code :
const getParameters = arg => {
const parameters = [];
const innerFunction = arg => {
parameters.push(arg);
return innerFunction;
};
return innerFunction(arg);
};
getParameters(1)(2)(5); // => expected value [1,2,5]
getParameters(1)(2)(5)(20); // => expected value [1,2,5,20]
const getParameters = a => b => c => [a, b, c];
console.log(getParameters(1)(2)(5));
UPDATE: Support unlimited arguments.
PS: only limitation is when you need to end the call, you have pass last call as null or undefined or empty as shown below.
const getParameters = a => {
const parameters = [a];
const innerFunction = b => {
if (b) {
parameters.push(b);
return innerFunction;
}
return parameters;
};
return innerFunction;
};
console.log(getParameters(1)(2)(5)());
console.log(getParameters(1)(2)(5)(9)(20)(22)());
Not very good solution, but... Try this one if you want to have a string in output.
function getParameters(a) {
let parameters = '[';
parameters += `${a}`;
function innerFunction(b) {
parameters += `,${b}`;
return innerFunction;
}
innerFunction.toString = function() {
return `${parameters}]`;
};
return innerFunction;
}
console.log(getParameters(1)(3)(4)); //[1,3,4]
If you can use a final parameter(like "x") to signify end, you can use .bind
const getParameters = function(...arg) {
if (arg[arg.length - 1] !== 'x') {
return getParameters.bind(null, ...arg);
}
arg.pop();
return arg;
};
console.info(getParameters(1)(2)(5)('x'));
console.info(getParameters(1)(2)(5)(20)("x"))
As we all know world of JavaScript is a magic world, and even this thing, like infinite currying is possible
const nice = (...args) => {
return Object.assign(
nice.bind(0, ...args),
{ valueOf: () => args.reduce((a, b) => a + b, 0) }
)
}
console.log(+nice(1)()(2)) // ~> 3
console.log(+nice(1, 2)()(3)()()) // ~> 6
console.log(+nice()()()()()()(1)) // ~> 1
console.log(+nice()()()(2)()()()) // ~> 2
console.log(nice(2)()(1) + '') // ~> '3'
console.log(nice()(3)() == 3) // ~> true
console.log(nice()(3)() === 3) // ~> false
The trick is that adding unary + or using non-strict equality calls valueOf method right after all function calls, so we've got ourselves an infinite currying :)
And list currying to answer your question. It works because '' + forces toString method to be called:
const nice = (...args) => {
return Object.assign(
nice.bind(0, ...args),
{ toString: () => JSON.stringify(args) }
)
}
console.log('' + nice(1,2)(3)(4)(5)(6,7)) // ~> [1,2,3,4,5,6,7]
By the way, it's possible to make this infinite currying even more legit, because it can take any type and any amount of parameters which's really cool.
<3
I want to be able to call fo and generate a string from within (the callee) that represents its "object address" or path e.g. "example.fee.set.fo".
Would this require a function that iterates over the "root" object (i.e example)?
The purpose is to reference who’s calling to the server side.
let example={
fee:{
set:{
fo(){
myName=????? //Here: generate a string with the value "example.fee.set.fo"
$.ajax({data:{WhosCalling:myName,foo:'bar'}});
},
}
}
}
Build a function that takes an object and the "root address" and recursively goes inside it, collecting the path to each nested function along the way.
Then wrap each of these nested functions with a function that accepts their arguments, apply them and return its address.
My recommendation would be that you keep your nested functions intact. But wrap them in a function that both executes them and talk to your server.
Example:
const communicate = (path, fn) =>
(...args) => {
const addr = path.join('.');
const exec = fn(...args);
console.log(`Call from ${addr}: ${exec}`); // or $.ajax()
return exec;
};
const baz = x => x + 10;
const baz_with_communicate = communicate(['foo', 'bar', 'baz'], baz);
baz_with_communicate(10);
//=>LOG: "Call from foo.bar.baz: 20"
//=> 20
So now you just don't do the "function with communicate" business, this is done for you automatically in the spy function.
Judging by your comments you seem to be struggling with the concept of functions taking functions as parameters and returning other functions. It is however a powerful concept that you should get familiar with as it would help you design powerful abstractions.
⚠️ This won't run on Edge (uses Object.fromEntries which is not supported yet)
const communicate = (path, fn) =>
(...args) => {
const addr = path.join('.');
const exec = fn(...args);
console.log(`Call from ${addr}: ${exec}`); // or $.ajax()
return exec;
};
const spy = (o, ...path) =>
Object.fromEntries(
Object
.entries(o)
.map(([k, v]) =>
v !== null && typeof v === 'object'
? [ k
, spy(v, ...path.concat(k))
]
: typeof v === 'function'
? [ k
, communicate(path.concat(k), v)
]
: [ k
, v
]));
const o_spy = spy(o, 'example');
console.log(o_spy.foo.bar.baz(5));
console.log(o_spy.bar.baz.bat(5));
<script>
const o =
{ foo:
{ bar:
{ baz: x => x + 10 }}
, bar:
{ baz:
{ bat: x => x + 20 }}};
</script>
Here's how I solved it!
let example={
fee:{
set:{
fo(){ let myName = arguments.callee.address;
console.log(myName); //I'm now able to get the location name of this function
//I can now use this to give context & identify myself to the server
//IE $.ajax({data:{WhosCalling:myName,foo:'bar'}});
},
}}};
function fn_addresses(obj,loc){
$.each(obj,function(k,v){ let _loc=(loc?loc+'.':'')+k; //#.each requires jQuery -- pure js: for(var i in this)
if(typeof v=='object'){ return fn_addresses(v,_loc) } //iterate through objects
//↓ Below binds the address (ie 'example.fee.set.fo') to the functions namespace ↓
if(typeof v=='function'){ v.address=_loc; }
});
}
fn_addresses(example,'example'); //traverse the object adding 'address' to nested functions
example.fee.set.fo();
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
Let's start with a definition: A transducer is a function that takes a reducer function and returns a reducer function.
A reducer is a binary function that takes an accumulator and a value and returns an accumulator. A reducer can be executed with a reduce function (note: all function are curried but I've cat out this as well as definitions for pipe and compose for the sake of readability - you can see them in live demo):
const reduce = (reducer, init, data) => {
let result = init;
for (const item of data) {
result = reducer(result, item);
}
return result;
}
With reduce we can implement map and filter functions:
const mapReducer = xf => (acc, item) => [...acc, xf(item)];
const map = (xf, arr) => reduce(mapReducer(xf), [], arr);
const filterReducer = predicate => (acc, item) => predicate(item) ?
[...acc, item] :
acc;
const filter = (predicate, arr) => reduce(filterReducer(predicate), [], arr);
As we can see there're a few similarities between map and filter and both of those functions work only with arrays. Another disadvantage is that when we compose those two functions, in each step a temporary array is created that gets passed to another function.
const even = n => n % 2 === 0;
const double = n => n * 2;
const doubleEven = pipe(filter(even), map(double));
doubleEven([1,2,3,4,5]);
// first we get [2, 4] from filter
// then final result: [4, 8]
Transducers help us solve that concerns: when we use a transducer there are no temporary arrays created and we can generalize our functions to work not only with arrays. Transducers need a transduce function to work Transducers are generally executed by passing to transduce function:
const transduce = (xform, iterator, init, data) =>
reduce(xform(iterator), init, data);
const mapping = (xf, reducer) => (acc, item) => reducer(acc, xf(item));
const filtering = (predicate, reducer) => (acc, item) => predicate(item) ?
reducer(acc, item) :
acc;
const arrReducer = (acc, item) => [...acc, item];
const transformer = compose(filtering(even), mapping(double));
const performantDoubleEven = transduce(transformer, arrReducer, [])
performantDoubleEven([1, 2, 3, 4, 5]); // -> [4, 8] with no temporary arrays created
We can even define array map and filter using transducer because it's so composable:
const map = (xf, data) => transduce(mapping(xf), arrReducer, [], data);
const filter = (predicate, data) => transduce(filtering(predicate), arrReducer, [], data);
live version if you'd like to run the code -> https://runkit.com/marzelin/transducers
Does my reasoning makes sense?
Your understanding is correct but incomplete.
In addition to the concepts you've described, transducers can do the following:
Support a early exit semantic
Support a completion semantic
Be stateful
Support an init value for the step function.
So for instance, an implementation in JavaScript would need to do this:
// Ensure reduce preserves early termination
let called = 0;
let updatesCalled = map(a => { called += 1; return a; });
let hasTwo = reduce(compose(take(2), updatesCalled)(append), [1,2,3]).toString();
console.assert(hasTwo === '1,2', hasTwo);
console.assert(called === 2, called);
Here because of the call to take the reducing operation bails early.
It needs to be able to (optionally) call the step function with no arguments for an initial value:
// handles lack of initial value
let mapDouble = map(n => n * 2);
console.assert(reduce(mapDouble(sum), [1,2]) === 6);
Here a call to sum with no arguments returns the additive identity (zero) to seed the reduction.
In order to accomplish this, here's a helper function:
const addArities = (defaultValue, reducer) => (...args) => {
switch (args.length) {
case 0: return typeof defaultValue === 'function' ? defaultValue() : defaultValue;
case 1: return args[0];
default: return reducer(...args);
}
};
This takes an initial value (or a function that can provide one) and a reducer to seed for:
const sum = addArities(0, (a, b) => a + b);
Now sum has the proper semantics, and it's also how append in the first example is defined. For a stateful transducer, look at take (including helper functions):
// Denotes early completion
class _Wrapped {
constructor (val) { this[DONE] = val }
};
const isReduced = a => a instanceof _Wrapped;
// ensures reduced for bubbling
const reduced = a => a instanceof _Wrapped ? a : new _Wrapped(a);
const unWrap = a => isReduced(a) ? a[DONE] : a;
const enforceArgumentContract = f => (xform, reducer, accum, input, state) => {
// initialization
if (!exists(input)) return reducer();
// Early termination, bubble
if (isReduced(accum)) return accum;
return f(xform, reducer, accum, input, state);
};
/*
* factory
*
* Helper for creating transducers.
*
* Takes a step process, intial state and returns a function that takes a
* transforming function which returns a transducer takes a reducing function,
* optional collection, optional initial value. If collection is not passed
* returns a modified reducing function, otherwise reduces the collection.
*/
const factory = (process, initState) => xform => (reducer, coll, initValue) => {
let state = {};
state.value = typeof initState === 'function' ? initState() : initState;
let step = enforceArgumentContract(process);
let trans = (accum, input) => step(xform, reducer, accum, input, state);
if (coll === undefined) {
return trans; // return transducer
} else if (typeof coll[Symbol.iterator] === 'function') {
return unWrap(reduce(...[trans, coll, initValue].filter(exists)));
} else {
throw NON_ITER;
}
};
const take = factory((n, reducer, accum, input, state) => {
if (state.value >= n) {
return reduced(accum);
} else {
state.value += 1;
}
return reducer(accum, input);
}, () => 0);
If you want to see all of this in action I made a little library a while back. Although I ignored the interop protocol from Cognitect (I just wanted to get the concepts) I did try to implement the semantics as accurately as possible based on Rich Hickey's talks from Strange Loop and Conj.
Following code add map method to function prototype so we are able to map our function, which basically composing map function with the result of mappable function. I understand that
Function.prototype.map = function (f) {
const g = this
return function () {
return f(g.apply(this, arguments))
}
}
But did not understand the following
const Box = x => ({
map: f => Box(f(x)),
fold: f => f(x),
inspect: () => `Box(${x})`
})
const nextCharForNumberString = str =>
Box(str)
.map(s => s.trim())
.map(s => new Number(s))
.map(s => s + 1)
.map(s => String.fromCharCode(s))
.fold(s => s.toLowerCase())
console.log(nextCharForNumberString(' 64 '));
Could you help me to understand that. Box is a function Box(x) and I am losing track after that.Why those parenthesis ( ({ })) and how that thing is working.
Thanks for your time and understanding,
By the way first code is taken from
https://medium.com/#dtinth/what-is-a-functor-dcf510b098b6
Second code is coming from egghead.io's functional javascript first lesson (it is a shame I just stuck in the first lesson)
It might help to inflate the code out of es6 syntax.
function Box(param) {
return {
map: function(fn) { return Box(fn(param)); },
fold: function(fn) { return fn(param) },
inspect: function() { return `Box(${param})`;
}
}
an example: let a = Box(1); returns the object from the Box function and gives you access to a.map, a.fold, or a.inspect
a.map takes a function as a parameter. let's say that function returned the value passed in plus 1
function myFunction(n) { return n + 1 };
you could call a.fold(myFunction) and the returned value would equal 2. This is because our initial param was 1, and our function takes that parameter as its argument and returns.
Basically fold applies whatever function to your param and returns it.
map is similar except that it returns Box(myFunction(1)) which returns a new Box object with a param + 1 since that's what our function mutated our param to.
inspect simply outputs a string that tells you what the current value of param is.
Overview:
function add1(n) { return n + 1 }
let a = Box(1); //param is 1.
a.fold(add1); //translates to add1(1);
a.map(add1); //translates to Box(add(1)), aka, Box(2)
a.inspect(); //translates to "Box(2)"
I've just started learning about functional programming and I'm trying to put into practice what I've learned. I've got this code below and I just don't know where can I apply function composition, partial application in this function.
Any ideas how to refactor this using the functional techniques?
function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn, codeA, codeB, param1, param2) {
let result = null;
if (validateFn(codeA, codeB)) {
const isCodeAValid = doStuffOnCodeAFn(codeA); // returns a boolean
const isCodeBValid = doStuffOnCodeBFn(codeB); // returns a boolean
const isItAMatch = moreProcessingFn(isCodeAValid, isCodeBValid, codeA, codeB); // returns a boolean
if (isItAMatch) {
result = doSomething1Fn (param1, param2);
} else {
result = doSomething2Fn (param1, param2);
}
}
return result;
}
The first step would be to get rid of all the helper variables. While the boolean intermediate variables ease understanding with their descriptive names, at least result is totally unnecessary.
function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn, codeA, codeB, param1, param2) {
return validateFn(codeA, codeB)
? (moreProcessingFn(doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB), codeA, codeB)
? doSomething1Fn
: doSomething2Fn
)(param1, param2)
: null;
}
Next you could apply some currying (you could do it per parameter, but I think it's more useful in the blocks that will likely be used together):
function compareCodes(validateFn, moreProcessingFn, doStuffOnCodeAFn, doStuffOnCodeBFn, doSomething1Fn, doSomething2Fn) {
return function(codeA, codeB) {
return validateFn(codeA, codeB)
? moreProcessingFn(doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB), codeA, codeB)
? doSomething1Fn
: doSomething2Fn
: function(param1, param2) { return null; };
};
}
But that's about it. While it would be possible to write your own combinators for the conditionals and the parallel feeding of multiple arguments into multiple functions, you will not gain anything in the process. There certainly are no standard combinators like composition that would help you out here.
It might be a different thing if you drop out of always supplying two things together (A and B, 1 and 2) but as distinct parameters. If you instead modify all of your functions to take tuples instead (here represented as arrays of length 2, given JavaScript's lack of a pair type), we can do something. First we convert from
function compareCodes(validateFn, moreProcessingFn, [doStuffOnCodeAFn, doStuffOnCodeBFn], [doSomething1Fn, doSomething2Fn], [codeA, codeB], [param1, param2]) {
return validateFn([codeA, codeB])
? (moreProcessingFn([doStuffOnCodeAFn(codeA), doStuffOnCodeBFn(codeB)], [codeA, codeB])
? doSomething1Fn
: doSomething2Fn
)([param1, param2])
: null;
}
to (I'm using ES6 syntax, notable arrow functions and destructuring)
const bimap = ([f, g]) => ([x, y]) => [f(x), g(y)];
const fst = ([x, _]) => x;
const snd = ([_, y]) => y;
function compareCodes(validate, moreProcessing, doStuff, doSomething, code, param) {
return validate(code)
? (moreProcessing(bimap(doStuff)(code), code)
? fst
: snd
)(doSomething)(param)
: null;
}
Now that is something we can indeed tackle with combinators:
const compose = f => g => x => f(g(x));
const bind = f => g => x => f(g(x), x);
const cond = pred => then => other => x => pred(x) ? then(x) : other(x);
const k = x => _ => x;
function compareCodes(validate, moreProcessing, doStuff, doSomething)
return cond(validate,
cond(bind(moreProcessing)(compose(bimap)(doStuff)),
fst(doSomething),
snd(doSomething)
),
k(k(null))
);
}
We could go further to a completely point-free definition of compareCodes, but honestly that's not worth it.