JS: Can a recursive function be decorated with cache? - javascript

We're going to make a decorator, caching computed results of deterministic functions (for simplisity let's assume one-argument functions).
In common case is could be done this way:
function makeCacheable(origFunc){
let registry = {};
return function (a){
if (a in registry){
return registry[a];
}
let res = origFunc(a);
registry[a] = res;
return res;
}
}
A problem appears when origFunc is recursive: only top-level calls go through the wrapping cache, but the rest of recursive call stack doesn't meet the cache. No need to explain why this happens. I wonder is there a natural way to make a recursive function cacheable in the same manner?
function fibonacciF(n) {
if (n <= 2) return 1;
let a = 1, b = 1;
for (let i = 2; i < n; ++i){
[a, b] = [b, a+b];
}
return b;
}
function fibonacciR(n) {
return n <= 2 ? 1 : (fibonacciR(n-1) + fibonacciR(n-2));
}
let fiboF = makeCacheable(fibonacciF); // OK
let fiboR = makeCacheable(fibonacciR); // actually is not what expected

The function calls a function named fibonacciR. If you want to make this call go through the cache, you have to overwrite fibonacciR:
fibonacciR = makeCacheable(fibonacciR);
Is there a natural way to make a recursive function cacheable in the same manner?
No. In general, a function implementation cannot be inspected, and it doesn't make a difference whether it's implemented recursively or with a loop or something else. Using pure functional programming, we can only use the whole function as a building block for the cached version (fiboR), but we cannot alter its behaviour or take only parts of the function unless the implementation is cooperative (e.g. by using some kind of recursion operator that can be user-supplied).
In the above solution, we break these rules by overwriting a variable that is used inside the function, but this is not always possible even in JavaScript.

You could make it work, if you would use the same (function) variable for storing the decorated version of it. To allow for returning back to the original, you could add a property original to the function object:
function makeCacheable(origFunc){
let registry = {};
let f = function (a){
if (a in registry){
console.log(`retrieving value from registry[${a}]`);
return registry[a];
}
let res = origFunc(a);
registry[a] = res;
return res;
}
// Add property for exposing the original function:
f.original = origFunc;
return f;
}
function fibonacciR(n) {
console.log(`Called fibonnacci(${n})`);
return n <= 2 ? 1 : (fibonacciR(n-1) + fibonacciR(n-2));
}
// Demo illustrating the registry is being used:
console.log('Call fibonnacciR(5) with cache turned on:');
var fibonacciR = makeCacheable(fibonacciR);
var f5 = fibonacciR(5);
console.log(`Result: fibonnaciR(5) = ${f5}`);
// Demo illustrating the function can be restored:
console.log('Call fibonnacciR(5) with cache removed:');
fibonacciR = fibonacciR.original;
f5 = fibonacciR(5);
console.log(`Result: fibonnaciR(5) = ${f5}`);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Was javascript argument default?

Is there a way to tell the difference between this
((a=true)=>{return a})(true)
And this?
((a=true)=>{return a})()
They both return true - how can I tell whether that true is coming from the default value of the argument, or from the value passed in to that parameter?
Is it possible from outside the function?
Is it possible from inside the function?
Is there a way to tell the difference between these two?
No. Arrow function doesn't support argument object, so there is no way to check this.
But, if you are using non-arrow functions, you can get arguments number from inside the function. For example:
(function(a=true){return arguments.length;})(); // 0
(function(a=true){return arguments.length;})(true); // 1
You can easily figure out how to extend this to multiple arguments.
You cannot tell the difference in your specific examples, and there is no way to tell from outside the function definitely. The only exposed info is what you explicitly expose with your return value, which is just the boolean.
From inside the function, you can tell the difference if you rewrite your logic. You could change your function from
((a=true)=>{
return a;
})(true)
to
((...args)=>{
const a = args[0] === undefined ? true : args[0];
if (args.length > 0) console.log("passed arg");
else console.log("passed no arg");
return a;
})(true)
Note that you cannot combine this with default value syntax, so if you'd have to rewrite it to use rest syntax.
Alternatively, you could use a normal function instead of an arrow, and use arguments, however that is also a potentially difficult change if your real-world case relies on the arrow-function's lexical this. e.g.
(function(a = true)=>{
if (arguments.length > 0) console.log("passed arg");
else console.log("passed no arg");
return a;
})(true)
Although not ideal in every way, one solution might be:
(a=undefined) => {
let is_default = false;
if (a === undefined) {
is_default = true;
a = true;
}
return a
}
If you really want to use arrow functions, you can achieve a robust (if convoluted) result using Symbol and a wrapping IIFE
var fn = ((def) =>
(a = def) => {
if(a === def) {
console.log('defaulted');
a = true;
}
console.log('a is', a);
}
)(Symbol());
both fn() and fn(true) will result in a is true - however, fn() will also output defaulted and then set a = true - though this last step I guess doesn't have to done, depends on what the real content of the real function you really want to "detect" this in
Or, a better way as pointed out by #Bergi (I keep forgetting about the block scope in ES6+ :D )
var fn;
{
const def = Symbol();
fn = (a=def) => {
if(a === def) {
console.log('defaulted');
a = true;
}
console.log('a is', a);
};
}

I'm trying to rewrite memoize in javascript (for underscore), can someone explain this?

I know that the purpose of memoize is to cache values so code can be run faster by not having to re-calculate the same answer everytime. My issue stems from returning a function (i think). The google chrome debugger isn't that useful for me here because everytime I try to run this memoize function, it just goes from the argus variable (on line 4 i believe) all the way down to the semi-colon. Furthermore, result always returns an empty object instead of storing a value in result.
I start by defining a function:
function add(a,b){
return a+b;
}
This is my attempt at the memoize function:
_.memoize = function(func) {
var result = {};
var flag = 0;
var argus = Array.prototype.slice.call(arguments)
return function() {
if(result[key] === arguments){
flag = 1
}
else if(flag = 0){
result[argus] = func.apply(this, argus);
}
return result[argus];
};
};
I'd call memoize by doing _.memoize(add(2,5)) but the result doesn't get stored in the result object.
Am I even close to getting this memoize function working properly? Any guidance you guys can give here would be appreciated.
The biggest point you're missing is that _.memoize is called on the function first, and it returns a new function. You are calling it on the result of a function call (which is the number 7 in this case).
In order to get it to work, you need to rearrange a few things.
Also note that it's not wise to try to use an array itself as the index to an object. One approach to get around that would be to convert the arguments array to JSON and use that as the index on the results object:
function add(a, b) {
console.log('Called add(' + a + ', ' + b + ')');
return a + b;
}
var _ = {};
_.memoize = function(func) {
var results = {};
return function() {
var args = Array.prototype.slice.call(arguments);
var key = JSON.stringify(args);
if (!(key in results)) {
results[key] = func.apply(this, args);
}
return results[key];
};
};
var madd = _.memoize(add);
console.log(madd(2, 4));
console.log(madd(9, 7));
console.log(madd(2, 4));

JS Function With Two Parentheses and Two Params

I'm trying to understand how a function works that is run with two parentheses and two parameters. Like so:
add(10)(10); // returns 20
I know how to write one that takes two params like so:
function add(a, b) {
return a + b;
}
add(10,10); // returns 20
How could I alter that function so it could be run with one set of parameters, or two, and produce the same result?
Any help is appreciated. Literally scratching my head over this.
Thanks in advance!
How could I alter that function so it could be run with one set of parameters, or two, and produce the same result?
You can almost do that, but I'm struggling to think of a good reason to.
Here's how: You detect how many arguments your function has received and, if it's received only one, you return a function instead of a number — and have that function add in the second number if it gets called:
function add(a,b) {
if (arguments.length === 1) {
return function(b2) { // You could call this arg `b` as well if you like,
return a + b2; // it would shadow (hide, supercede) the one above
};
}
return a + b;
}
console.log(add(10, 10)); // 20
console.log(add(10)(10)); // 20
I said "almost" above because just because the add function received only one argument, that doesn't guarantee that the caller is going to call the result. They could write:
var x = add(10);
...and never call the function that x now refers to.
Welcome to the wonderful world of first order functions
In JavaScript, a function can return a function since a function is just another object. A simple implementation is something like:
function add(x){
return function addOther(y){
return x + y;
};
}
This is possible because of closures and first order functions.
This also lets you do partial application, libraries like Ramda utilize this to great extent.
var addThree = add(3)
addThree(5); // 8
To extend what both T. J. Crowder and Benjamin Gruenbaum said, libraries like Ramda (disclosure: I'm one of the authors) allow you to convert a simple function like this:
function add(a, b) {
return a + b;
}
into the style under discussion by wrapping it in a call to a curry function:
var add = R.curry(function add(a, b) {
return a + b;
});
add(3, 5); //=> 8
add(3)(5); //=> 8
var add3 = add(3);
add3(5); //=> 8
The best article I know on this subject is Hugh Jackson's Why Curry Helps. I wrote a more detailed one at Favoring Curry.
Update
Here is a version of curry somewhat simpler than the one in Ramda. It would do the above and quite a bit more, but doesn't do some of the things that Ramda does with placeholder values:
// here is a function that takes a function and returns a curried version
// of it, that is, a version that performs the sort of partial application
// you describe.
var curry = function(fn) {
// first, we detect how many arguments the function has.
var fnArity = fn.length;
var partialApply = function(args) {
// now, let's create a function that's curried
return function () {
// collect the previous args as the partial, and add the new
// ones you just received
var newArgs = (args || []).concat([].slice.call(arguments, 0));
// if we have "enough" arguments, we don't need any more partial
// application and we can call the function.
if (newArgs.length >= fnArity) {
return fn.apply(this, newArgs);
} else { // else we return a partially applied version
return partialApply(newArgs);
}
};
};
return partialApply([]); // a function is itself partially applied with 0 args
};
function add() {
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
function total() {
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return total;
}
total.toString = function () { return sum };
return total;
}
This will work for any no of arguments and parentheses.
https://medium.com/#imdebasispanda/super-function-with-closure-86a58a9a980b

Higher Order Internal Memoization In JavaScript does not Work

Context.
Memoization is a functional technique operating over recursive functions with overlapping invocations aiming to optimize time performance by using an internal cache that remembers previous results with already used parameters. A typical use case is the fibonacci function. Below, it is shown a non memoized and memoized version of that function and an assisting function for timing purposes:
function time (fn) {
return function () {
var before = Date.now();
var result = fn.apply(this, arguments);
var after = Date.now();
return {
value : result,
time : after - before
};
};
}
var fib = function (n) {
if (n < 2) return n;
else return fib(n-1) + fib(n-2);
};
var mfib = function (n) {
var cache = {};
var memoizefib = function (n) {
if (n < 2) return n;
else {
var k1 = JSON.stringify(n-1);
var k2 = JSON.stringify(n-2);
var v1 = k1 in cache ? cache[k1] : (cache[k1] = memoizefib(n-1));
var v2 = k2 in cache ? cache[k2] : (cache[k2] = memoizefib(n-2));
return v1 + v2;
}
};
return memoizefib (n);
};
If now we test our functions we realize that memoization dramatically reduces execution time:
(function test (n) {
var tfib = time(fib);
var tmfib = time(mfib);
console.log(tfib(n)); // -> { value: 433494437, time: 5780 }
console.log(tmfib(n)); // -> { value: 433494437, time: 1 }
})(43);
Problem.
As it frequently happens in functional programming, memoization becomes a useful tool when applied at the higher order to allow defining a memoize function that can transform over a generic function fn. Typical solutions similar to the next one can be found on the Web [1][2][3]:
function memoize (fn) {
var cache = {};
return function () {
var args = [].slice.call (arguments);
var key = JSON.stringify(args);
return key in cache ?
cache[key] :
cache[key] = fn.apply(this, args); (1)
};
}
fn.js - http://eliperelman.com/fn.js
underscore - http://underscorejs.org
Addy Osmani on Memoization - http://addyosmani.com/blog/faster-javascript-memoization
Question.
Nevertheless, surprisingly none of these solutions works!!! After revolving around the code. I think that the problem is in (1) because the recursion it is not applied over the memoized version of fn but over primitive fn and hence memoization is only applied once. Here are my results:
(function test (n) {
var tfib = time(fib);
var tmfib = time(memoize(fib));
console.log (tfib(n)); // -> { value: 433494437, time: 5768 }
console.log (tmfib(n)); // -> { value: 433494437, time: 5723 } :(
})(43);
It seems that in Javascript it is not possible to apply this technique at higher order. Am I right? Does anybody have any solution or alternative code to get a higher order memoization function?
Interesting problem. Why not just memoize the function onto itself?
function factorial(n) { return n ? n * factorial(n-1) : 1; }
// simple memoization with one argument and console reporting
function memoize(fn) {
var cache = {};
return function(x) {
if (x in cache) { console.log('retrieved value from cache for', x); }
return x in cache ? cache[x] : cache[x] = fn.apply(this, arguments);
};
}
// redefine factorial to be its memoized version
factorial = memoize(factorial);
Once you do this, factorial will now be calling its memoized version.
> factorial(6)
720
> factorial(7)
retrieved value from cache for 6
5040
Applying this to your case (no need for mfib):
(function test (n) {
var tfib = time(fib);
console.log(tfib(n));
fib = memoize(fib); // <-- memoize on top of itself
var tmfib = time(fib);
console.log(tmfib(n));
})(30);
Results:
Object {value: 832040, time: 714}
Object {value: 832040, time: 22}
Note that this solution very much applies to "internal memoization" used within a single recursive computation, not just additional external calls to the function as in the factorial case above. By redefining the function with its memoized version, the internal recursive calls are now made to the memoized function. That accounts for the dramatic time improvement from 714 to 22.
If you are looking for "internal" memoization within a single recursive computation, the factorial function (which is given in the currently accepted answer - which BTW I also think is wrong) is a bad candidate and can't be used to showcase it. This is because, there's a single chain of recursion, so once you compute, e.g. the value for 5! you are not going to need it again within the same computation. To showcase what you are asking for, you would indeed need to use an example like the Fibonnaci sequence (which you are yourself using in the question).
The higher-order memoize function you wrote will not work internally within the same computation as it is calling the non-memoized version of it. The currently accepted answer suggests "redefining" the function to be its memoized version. However I think this is wrong. The memoize function closes over the function it was provided with as an argument (functions are values). Changing the variable that used to point to that function value to some other function value (the memoized version) accomplishes nothing.
So, I don't think it is possible to generalize it. That is, I don't believe it is possible to implement a memoize function that externally memoizes a function and makes it work also for a single recursive computation.
Here's what would work for Fibonnaci (like I said, not generalizable):
var fib = (function() {
function fib(n) {
if ((n===1) || (n==2))
return 1;
else
return memoizedFibonacci(n-1)+memoizedFibonacci(n-2);
}
var cache = {};
function memoizedFibonacci(n) {
if (n in cache) { console.log('retrieved value from cache for', n); }
return n in cache ? cache[n] : cache[n] = fib(n);
};
return fib;
})();
console.log(fib(10));
console.log(fib(10));
The above code produces on the output:
retrieved value from cache for 2
retrieved value from cache for 3
retrieved value from cache for 4
retrieved value from cache for 5
retrieved value from cache for 6
retrieved value from cache for 7
retrieved value from cache for 8
55
retrieved value from cache for 9
retrieved value from cache for 8
55
... which is consistent with the expectation for "internal memoization" for the first recursive computation. That the value for 10 is not cached is insignificant for this example and could be trivially fixed but it would add very little (basically you would need to access the cache from the fib function as well).

Javascript recursivity check

Is there a built-in way to check if a javascript function has been called recursively (directly or indirectly)?
By recursively, I mean that the function could be anywhere in the recursion chain (the function doesn't have to be the direct invoker).
EDIT
Obviously, there's no built-in way to achieve what I want to do. I though the plan B would be easy to implement so I came up with this solution (similar to Paolo answer):
function checkRecursion() {
var f = arguments.callee.caller;
var caller = f;
while (caller) {
caller = caller.caller;
if (caller === f) {
return true;
}
}
return false;
};
This function is working perfectly if you try to search the first recursive level.
function fA() {
if (checkRecursion()) {
alert("End of recursion");
}
else {
fB();
}
}
function fB() {
fA();
}
fA();
However, if you need to perform the same check on a function executed after an other recursion, you'll end up into an infinite loop:
var count = 0;
function fA() {
if (checkRecursion()) {
//I should get here but I get stuck in the checkRecursion()
alert("End of recursion");
}
else {
fB();
}
}
function fB() {
if (count > 2) {
fA();
} else
{
count++;
fC();
}
}
function fC() {
fB();
}
fA();
For some reason, the fB caller is fC, and the fC caller is fB so I can't travel back to the fA function as a caller of fB. This issue is way more complicated than I though it would be.
If you reflect on it, what you are getting makes perfect sense because every function in your code is a single object.
caller is a reference to that object and the latter is always the same and so they are its instance variables' values.
In other words, if a function is present more than once in the stack trace then it's "caller" appears to be always the most recent caller. That's why your function fails to go up the stack trace and ends in a infinite loop in the above case.
Let's make an example:
a => b => c => d => b => e => checkRecursion
The above is the stack trace that ends in checkRecursion at the deepest level.
b is called the first time from a the second time from d.
But what you get from caller is that b is always called from d !
It cannot have two callers because the object/function is always the same.
Climbing the stack trace you get
e <= b <= d <= c <= b <= d <= c <= b <= d...
You never reach a
To achieve what you need you may obtain the stack trace with another technique that, unfortunately, is not cross browser.
Below there is a modified version of checkRecursion that uses that technique. I tested it on Firefox, it doesn't work on Safari.
// returns true if the caller appears more than once
// in the stack trace
function checkRecursion()
{
// the name of the calling function
var fname = checkRecursion.arguments.callee.caller.name;
// obtain the stack trace ***not cross browser***
// tested on Firefox
var err = new Error();
var stack = err.stack.split('\n');
// returns true if the calling function appears more than once
var i,n,cnt;
n = stack.length;
cnt = 0;
for( i = 0; i < n; i++ )
{
if( fname == stack[i].substr(0,stack[i].indexOf('#')) )
{
cnt++;
if( cnt > 1 )
{
return true;
}
}
}
return false;
}
You can use the Chrome Developer Tool (if you use chrome) and start a new "Timeline" audit.
If you filter the result to show only the functions, you should be able to find some functions called by time.
Another thing to try is a "profile" audit to collect JavaScript CPU Profile. If you see a function name with an high percentage, that means it's using more resources and it may also be called multiple times.
Using Function.caller, you can check which function invoked your function. Check it against the last caller to see if they're the same function.
var y = function() {
console.log(this.lastCaller === y.caller);
this.lastCaller = y.caller;
}
var x = function(i) {
y();
if(i) {
x(--i);
}
}
x(3);
Outputs:
false, true, true, true

Categories