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>
Related
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.
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'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.
In Knockout I have observable variable location. It is of type LocationEdit. This viewModel has observable and not fields.
I have collection of field names : fields. For each field I want to reset values for location
fields.forEach(field => {
if (this.uniqueField(locs, field)) {
if (ko.isObservable(this.location()[field])) {
this.location()[field](locs[0][field]);
} else {
this.location()[field] = locs[0][field];
}
}
});
To make this code more simpler (remove if-clauses), Can I somehow set value to this.location()[field] in one line?
You could use the conditional operator (... ? ... : ... ;) although it doesn't change much:
fields.forEach(field => {
if (this.uniqueField(locs, field)) {
ko.isObservable(this.location()[field]) ? this.location()[field](locs[0][field]) : this.location()[field] = locs[0][field];
}
});
Or you could write a function:
function upd(arr, index, val) {
ko.isObservable(arr[index]) ? arr[index](val) : arr[index] = val;
}
Usage:
fields.forEach(field => {
if (this.uniqueField(locs, field)) {
upd(this.location(), field, locs[0][field]);
}
});
See demo.
You could even add this function to ko:
if(typeof ko.updatePotentialObservable == 'undefined')
ko.updatePotentialObservable = function (arr[index], val) {
ko.isObservable(obj) ? arr[index](val) : arr[index]= val;
}
Usage:
fields.forEach(field => {
if (this.uniqueField(locs, field)) {
ko.updatePotentialObservable(this.location(), field, locs[0][field]);
}
});
See other demo
To be honest, I think Gôtô's answers are definitely your best options. Basically, you'd want to create a utility function similar to ko.unwrap but setting a value.
But since you said "also want to find another solution", here's a different utility function. I think the most confusing part of your code is the returning calls to locs[0][field] and this.location()[field]. I'd want something with this signature:
reset(source, target, keys);
So, in your code, you could do:
reset(
this.location(),
locs[0],
fields.filter(f => this.uniqueField(locs, f))
);
Now, writing this method, I ended up with this:
const mergePropsObs = (function() {
// Return a method for setting a specific property in object
const getSetter = obj => prop => ko.isObservable(obj[prop])
? obj[prop]
: val => obj[prop] = val;
// Return unique keys for two objects
// (I went with a quick oneliner; there are many ways to do this)
const allKeys = (obj1, obj2) =>
Object.keys(Object.assign({}, obj1, obj2));
return (base, ext, onlyProps) => {
const props = onlyProps || allKeys(base, ext);
const values = props.map(p => ko.unwrap(ext[p]));
props
.map(getSetter(base))
.forEach((setter, i) => setter(values[i]));
};
}());
var base = { a: 1, b: ko.observable(2), c: 5 };
mergePropsObs(
base,
{ a: 2, b: 3 },
["a", "b"]);
console.log(base.a);
console.log(base.b());
console.log(base.c);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
This utility method can be used with the signature mentioned above. It also has a fallback for when you don't provide an array of field names.
I'm calling some database functions from my request handlers. All of these functions do separate "error callbacks" for handling errors. Example:
function referralComplete(req, res) {
/*getting id etc.*/
db.startDatabaseConnection(function() {
db.flagReferralAsDone(id, function(success) {
db.endDatabaseConnection();
/*doing stuff on success*/
}, onError);
}, onError);
function onError(err, description) {
logger.error(description + ": " + err);
user.pageNotFound(req, res);
}
}
I have several request handlers similar to this all calling different database functions. At the moment I have duplicated onError() into the scope of each of them since I need req and res when handling the error, but I like think that there might be a way to achieve the same without the duplication.
So the question is, would it be possible to somehow bind req and res to onError() so that I won't have to duplicate onError() into each request handler?
Binding is simple!
db.startDatabaseConnection(function(){
// whatever
}, onError.bind(this, var1, var2));
You can learn more about binding by clicking this awesome link, even though the link is sort of long.
Here's a real basic demo
// a function
var something = function (a, b, c) {
console.log(a, b, c);
};
// a binding of something with 3 defined args
var b = something.bind(null, 1, 2, 3);
// call b
b();
//=> 1 2 3
Behind the scenes, this is basically what's happening
// ES6
const myBind = (f, context, ...x) =>
(...y) => f.call(context, ...x, ...y);
// ES5
var myBind = function(fn, context) {
var x = Array.prototype.slice.call(arguments, 2);
return function() {
var y = Array.prototype.slice.call(arguments, 0);
return fn.apply(context, x.concat(y));
};
};
var b = myBind(console.log, console, 1, 2, 3);
b();
// => 1 2 3
b(4,5,6)
// => 1 2 3 4 5 6
Context?
Context allows you to dynamically change the this of your function. Note you can only bind the context of functions defined with the function keyword; arrow functions have a lexical this that cannot be manipulated. This is shown for sake of completeness, but I do advise against this kind of program. It's usually better to just use another function parameter instead of relying on dynamic function context, this. Supporting context switching like this is to enable object-oriented style in JavaScript. Unless you are using this style, I see no reason to pay attention to context.
const getCanvas = (id) =>
document.getElementById(id).getContext('2d')
const draw = function (canvas, x = 0, y = 0)
{ canvas.beginPath()
canvas.strokeStyle = this.color // `this` refers to context!
canvas.rect(x, y, this.width, this.height) // `this` refers to context!
canvas.stroke()
}
// create two contexts
const contextA =
{ color: 'blue', width: 10, height: 10 }
const contextB =
{ color: 'green', width: 10, height: 20 }
// bind the draw function to each context and the canvas
const drawA =
draw.bind(contextA, getCanvas('main'))
const drawB =
draw.bind(contextB, getCanvas('main'))
// call the bound drawing functions normally
// draw three blue squares
drawA(0, 0)
drawA(20, 0)
drawA(40, 0)
// and one green rect
drawB(80, 0)
<canvas id="main"></canvas>
Partial application
Similar to binding is Partial Application
In computer science, partial application (or partial function application) refers to the process of fixing a number of arguments to a function, producing another function of smaller arity.
Here we could make a very simple partial helper procedure which helps us accomplish this
const identity = x =>
x
const partial = (f = identity, ...x) =>
(...y) => f (...x, ...y)
const foo = (...all) =>
console.log ('array of', all)
partial (foo, 1, 2, 3) (4, 5, 6)
// 'array of', [ 1, 2, 3, 4, 5, 6 ]
Currying
Currying is related to, but not the same as, binding or partial application
In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.
const identity = x =>
x
const curry = (f = identity, arity = f.length) => x =>
{
const next = (xs = []) =>
xs.length >= arity
? f (...xs)
: x => next ([ ...xs, x ])
return next ([ x ])
}
const foo = (a, b, c) =>
console.log ('a', a, 'b', b, 'c', c)
curry (foo) (1) (2) (3)
// 'a' 1 'b' 2 'c' 3
curry (foo) ('choo') ('bye') ()
// 'a' 'choo' 'b' 'bye' 'c' undefined