Curried functions: how to optimize them - functional-programming

I'm relatively new to functional programming and libraries such as ramda.js but one thing I found very useful is the possibility of currying functions.
Using curried functions I write very often things as the following
const myFun = R.curry(
(arg1, arg2) => {
let calculated = anotherFun(arg1)
//do something with calculated and arg2
return calculated * 5 + arg2
}
)
const anotherFun = (arg) => {
console.log("calling anotherFun");
return arg + 1
}
var partial = myFun(1)
console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>
but clearly in this situation anotherFun is called every time I call partial even if in arg1 and as a consequence calculated are always the same.
Is there a way to optimize this behaviour and call anotherFun only when its args change?
The only way that crosses my mind is this
const myFun = R.curry(
(calculated, arg2) => {
return calculated * 5 + arg2
}
)
const anotherFun = (arg) => {
console.log("calling anotherFun");
return arg + 1
}
var calculated = anotherFun(1)
var partial = myFun(calculated)
console.log(partial(2))
console.log(partial(3))
<script src="//cdn.jsdelivr.net/ramda/0.22.1/ramda.min.js"></script>
but in this way I have to change the arguments passed to myFun and this complicates the external API

If you do the currying manually like this
const myFun = arg1 => arg2 => {
let calculated = anotherFun(arg1)
// do something with calculated and arg2
return calculated * 5 + arg2
};
you can also make this optimisation:
const myFun = arg1 => {
let calculated = anotherFun(arg1);
return arg2 => {
// do something with calculated and arg2
return calculated * 5 + arg2
};
};
I don't think Ramda will help you here with anything; and JavaScript compilers certainly are not doing this kind of optimisation.

#Bergi is right that Ramda will not offer you any help with this. If you want a Ramda-style result, where you can call with one parameter to get a function back or both to get the result you can do this:
const myFun = function(arg1, arg2) {
let calculated = anotherFun(arg1);
const newFunc = arg2 => {
return calculated * 5 + arg2
};
return (arguments.length < 2) ? newFunc : newFunc(arg2);
};
const with3 = myFun(3);
//: calling anotherFun
with3(1); //=> 21
with3(2); //=> 22
with3(4); //=> 23
myFun(2, 7);
//: calling anotherFun
//=> 22
myFun(2, 8);
//: calling anotherFun
//=> 23
This comes at the cost of not being able to use ES2015 arrow functions. But it might be worth it to you.
You can also rework this slightly to not build the internal function if both parameters are supplied, if that is important to you.

How about useWith and memoize from Ramda?
const myFun = R.useWith(
(a, b) => a * 5 + b,
[R.memoize(anotherFun), R.identity]
);

Related

Ramda applySpec - keep unmodified props

Let's say I have an object const foo = { a: 1, b: 2 } and I want to add a prop c which is based on b.
I could do:
applySpec({
a: prop('a'),
b: prop('b'),
c: ({ b }) => b + 1
}, foo)
and get an object like: { a: 1, b: 2, c: 3 }
Is there a nicer way to do this?
I've looked at evolve, assoc and applySpec but none of them seems to be fit for purpose.
You can use R.chain to create a function that apply the spec, and then merges the new object with the original one.
If R.chain is used with function (f & g):
chain(f, g)(x) is equivalent to f(g(x), x)
In this case chain(mergeLeft, applySpec({})) is equal to mergeLeft(applySpec({}), originalObject).
const { chain, mergeLeft, applySpec } = R
const fn = chain(mergeLeft, applySpec({
c: ({ b }) => b + 1
}))
const foo = { a: 1, b: 2 }
const result = fn(foo)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
You can make this a generic function that allows adding to existing object, by using R.pipe to pass a curried R.applySpec to the chain:
const { pipe, chain, mergeLeft, applySpec } = R
const fn = pipe(applySpec, chain(mergeLeft))
const addCProp = fn({
c: ({ b }) => b + 1
})
const foo = { a: 1, b: 2 }
const result = addCProp(foo)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

Sinon stub argument return fake callback

I just want to know if it is possible to fake a callback on a stub argument.
This is basically what I want to achieve and I found nothing on Sinon's documentation:
function A(arg1, arg2, next){
return [arg1, arg2, next];
};
function B(string){
return string;
};
function C(){
return 'Mocked next';
};
var obj = {
A: A,
test: 'test'
};
var result1 = obj.A(1, 2, B('Next')); // result1 = [1, 2, 'Next']
sandbox.stub(obj, 'A')//.Argument[2].Returns(C());
var result2 = obj.A(1, 2, B('Next')); // result2 = [1, 2, 'Mocked next']
Is it possible?
Yes, it is possible.
sinon doesn't provide a way to directly mock an argument of a stub, but it does provide callsFake which lets you create your own implementation.
You can create a stub that calls the original implementation with the result of C() passed as the third argument like this:
const original = obj.A; // capture original obj.A
sandbox.stub(obj, 'A').callsFake((...args) => original(args[0], args[1], C()));
const result = obj.A(1, 2, B('Next'));
sinon.assert.match(result, [1, 2, 'Mocked next']); // SUCCESS

Either Monad: How to collect all the Right values and do work with all of them at the end?

So what I am trying to do is collect all the Right values from a series of Either results and have all of them available at the end of the chain to do work on them. I also want the chain to fail fast if one of the Either values is a Left.
So after reading around I believe the key to getting this all to work is a combination of a curried function and an applicative functor.
Below is sample code I have so far that is not quite working. Note that I am using monet.js and lodash:
const test1 = Right('test1');
const test2 = Left('test2');
const test3 = Right('test3');
function success(val, val2, val3){
return {
val, val2, val3
};
}
const curriedFn = _.curry(success);
Right(curriedFn)
.ap(Right(function(fn){
return fn(test1);
}))
.ap(Right(function(fn){
return fn(test1);
}))
.ap(Right(function(fn){
return fn(test1);
}))
.map(function(res){
console.log(res);
});
At the very end I get an object that contains 3 Either values that looks like this:
{ val: { isRightValue: true, value: 'test1' },
val2: { isRightValue: true, value: 'test1' },
val3: { isRightValue: true, value: 'test1' } }
What I want is the 3 actual values. And if you see, one of the Either values is a Left and the chain should have been broken.
I am trying to do this in a pure functional way. That is why I am not mapping and stuffing values in an object out of the scope of the functions.
Any ideas? Alternatives?
It looks like you're using .ap incorrectly
const Either =
require ('data.either')
const { Left, Right } =
Either
const success = x => y => z =>
[ x, y, z ]
const a =
Right (1)
const b =
Right (2)
const c =
Right (3)
const badegg =
Left ('badegg')
If success is applied to badegg for any param, the immediate result will be a Left. Subsequent calls to .ap will not affect the Left
Right (success)
.ap (a)
.ap (b)
.ap (c)
.fold (console.error, console.log) // [ 1, 2, 3 ]
Right (success)
.ap (badegg)
.ap (b)
.ap (c)
.fold (console.error, console.log) // "badegg"
Right (success)
.ap (a)
.ap (badegg)
.ap (c)
.fold (console.error, console.log) // "badegg"
Right (success)
.ap (a)
.ap (b)
.ap (badegg)
.fold (console.error, console.log) // "badegg"
So I misread the docs: https://monet.github.io/monet.js/#maybe
You need to nest the successive .ap calls. Below is a reworked example of what I was trying to do above:
const test1 = Right('test1');
const test2 = Right('test2');
const test3 = Right('test3');
const success = _.curry(function (val, val2, val3){
return {
val,
val2,
val3
};
});
test3.ap(test2.ap(test1.map(success)))
.map(success => {
console.log(success)
});
I am sure there is a elegant way with compose or some other monad to flatten the chain out, but for the time being I am satisfied.

How can I convert this large factorial function to a higher-order function?

The following code uses a cache object outside of the factorial function. The factorial function itself is large which has too many concerns of finding factorial and caching.
How can I convert this code to a higher-order function and generate the same result when I call
console.log(factorial(5));
console.log(factorial(7));
cache = { }
function factorial(n) {
if (n === 0) {
return 1;
}
if (cache[n])
{
return cache[n];
}
console.log("Stack Up: " + n);
var value = n * factorial(n - 1);
console.log("Stack Down: " + value);
cache[n] = value;
return value;
}
console.log(factorial(5));
console.log(factorial(7));
There's already other answers out there for memoising recursive functions, but I'll adapt that answer to factorial in javascript so you can see how it works more easily
The secret to writing memoised recursive functions is continuation passing style. A similar technique works when you want to make a non-tail recursive function stack-safe.
I'll leave some console.log statements in this first example so you can see when it's actually computing and when it's just doing a memo lookup.
const memoise = f => {
const memo = new Map()
const compute = (x, k) =>
(console.log('compute', x),
memo.get(x, memo.set(x, f(x,k))))
const lookup = x =>
(console.log('lookup', x),
memo.has(x) ? memo.get(x) : compute(x, lookup))
return lookup
}
const factk = (x, k) => {
if (x === 0)
return 1
else
return x * k(x - 1)
}
const memfact = memoise(factk)
console.log(memfact(5)) // 120
console.log(memfact(7)) // 5040
Here I've removed the console.log calls inside of memoise and instead demonstrate a memoised fibonacci function vs an unmemoised one. Compare the dramatic time difference between memoise(fibk) and badfib
const memoise = f => {
const memo = new Map()
const compute = (x, k) =>
memo.get(x, memo.set(x, f(x,k)))
const lookup = x =>
memo.has(x) ? memo.get(x) : compute(x, lookup)
return lookup
}
const fibk = (x, k) => {
if (x < 2)
return x
else
return k(x - 1) + k(x - 2)
}
const badfib = x => {
if (x < 2)
return x
else
return badfib(x - 1) + badfib(x - 2)
}
console.time('memoised')
console.log(memoise (fibk) (35)) // 9227465 1.46ms
console.timeEnd('memoised')
console.time('unmemoised')
console.log(badfib(35)) // 9227465 135.85ms
console.timeEnd('unmemoised')

Passing a variable to setTimeout()

I've installed a Jcarousel on Drupal 7 but I need it to scroll horizontally to both sides when the client hovers over the arrows.
I've been trying to pass a variable to the Timeout function and it doesn't seem to work.
In the following code Timeout recognizes only: var n = function () {c.next();};
I need to be able to tell timeout to either scroll left or right using c.prev() or c.next() depending on which arrow the user clicked.
var c = this;
var k = 1;
var n = function () {c.next();};
if (k == 1) n = function () {c.prev();};
if (k == 5) n = function () {c.next();};
this.timer = window.setTimeout(n, 500)
I've also tried to do it this way and it doesn't work either.
var c = this;
var k = 5;
this.timer = window.setTimeout(function() {c.nextprev(k);}, 500)
...
nextprev: function(k) {
if (k === 1) return "prev()";
if (k === 5) return "next()";
}
Any help or guideline will be appreciated!
Try this, it doesn't feel 100% right, but introduces some techniques you seem to need:
c.nextprev to execute immediately and return a function that will do what was really needed, capturing c and k as a closure...
c.nextprev = function(k){
return function(){
// I feel like prev and next might be backwards... think about that
if (k === 1) c.prev();
if (k === 5) c.next();
// do nothing if k not 1 nor 5
}
};
c.timer = window.setTimeout(c.nextprev(k), 500);
...or maybe just do this without all the preceding code....
Here bind sets "this" back to c.
setTimeout( (k === 5)? c.next.bind(c): ((k === 1)? c.prev.bind(c): function(){} ) );

Resources