How underscore memoize is implemented in javascript - javascript

I'm developing my own functional-programming library, and now referring the underscore.
memoize _.memoize(function, [hashFunction])
Memoizes a given function by caching the computed result. Useful for speeding up slow-running computations. If passed an optional hashFunction, it will be used to compute the hash key for storing the result, based on the arguments to the original function. The default hashFunction just uses the first argument to the memoized function as the key.
var fibonacci = _.memoize(function(n) {
return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});
The above code that enables automatic memorisation without dealing array looks sort of magic, and I saw the source-code below, but still the inner design is not clear to me.
// Memoize an expensive function by storing its results.
_.memoize = function(func, hasher) {
var memoize = function(key) {
var cache = memoize.cache;
var address = hasher ? hasher.apply(this, arguments) : key;
if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
return cache[key];
};
memoize.cache = {};
return memoize;
};
Can someone give me a brief idea of what is going on?
Appreciated.

memoize has a cache (memoize.cache = {}) that uses for storing the result of the function call. When it's called, it determines an address to store the result by two means: either a call to the hasher function, or the key parameter.
The hasher function works like this (from the underscore page):
If passed an optional hashFunction, it will be used to compute the
hash key for storing the result, based on the arguments to the
original function. The default hashFunction just uses the first
argument to the memoized function as the key.
Then, it calls the function you passed func.apply(...), and stores the result at cache[address].
The second time you call the memoized function, the result will already be in cache (!_.has(..) will return false) and the computation won't be repeated.
I dont' understand why it returns cache[key] and not cache[address] tough...seems to me that cache[address] would be the correct choice.
Update
As pointed out in the comments, the code you present is not the latest implementation of memoize. This is the latest implementation (1.6.0):
_.memoize = function(func, hasher) {
var memo = {};
hasher || (hasher = _.identity);
return function() {
var key = hasher.apply(this, arguments);
return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
};
};
It works the same way, except from the fact that it is a little more elegant; if an hasher function it's not provided, it uses _.identity as a key, that is a function that simply returns the value passed as an argument:
_.identity = function(value) { return value; }
Aside from this, cache is now called memo but works the same way.

Related

function()(function) in javascript what does this syntax standard? [duplicate]

I was looking how filters works in Angularjs and I saw that we need to send 2 sets of parentheses.
$filter('number')(number[, fractionSize])
What does it means and how do we handle it with JavaScript?
It means that the first function ($filter) returns another function and then that returned function is called immediately. For Example:
function add(x){
return function(y){
return x + y;
};
}
var addTwo = add(2);
addTwo(4) === 6; // true
add(3)(4) === 7; // true
$filter('number') returns a function that accepts two arguments, the first being required (a number) and the second one being optional (the fraction size).
It's possible to immediately call the returned function:
$filter('number')('123')
Alternatively, you may keep the returned function for future use:
var numberFilter = $filter('number');
numberFilter('123')
It is the same as this:
var func = $filter('number');
func(number[, fractionSize]);
The $filter() function returns a pointer to another function.
with ES6 or later versions you can do it that way;
const divideBoth = (x) => (y) => {
return x / y;
};
one of the reasons that makes this function type useful is when you have a react.js component that needs have callback function instead of doing it inline way(which is ()=>return value) you can do it the way we did previously. But it is not recommended to use in event callbacks because it gets execute in the first render which might cause issues sometimes

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));

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).

Is it possible to redefine parts of a javascript function without changing the behaviour?

I need to define a callback, which is to be called by a external library. This callback is called with 1 parameter:
function(item) {};
In my case I need to include a second parameter which I currently solve by using the 'bind' method.
function(item) {
var value = this.value
}.bind({'value': value});
I dont want to write this every time I need to define shuch a callback function. Instead I would like to write something like this:
function(item, value) {};
Which then would be transformed into the bind method in order to satisfy the external library.
Is that possible? Or is there some other way to do this?
Thanks
You want to use closures. Here's the basic pattern, though not quite as easy as what georg suggested. But performance-wise, not nearly as much of a hit (near minimal).
Define a function:
myValueFunction(value, fn){
return fn;
}
Since it seems you're saying your plugin is providing item and you are providing the value, you will set myValueFunction(yourvalue, function(item){}) as the callback function for your plugin (with your actual value as the parameter). It'll "return" another function with your value enclosed that takes one argument (item).
So for example if you have a plugin:
var myValue= "x";
plugin.doSomething("Plugin Argument", myValueFunction(myValue, function(item){
console.log(item, value);
}));
This is basically what georg's answer is doing (his is in a somewhat more versatile way), but his method will will be much slower performance-wise than if you define these functions directly, particularly if you start adding many arguments.
You can use the function.partial implementation from here:
Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for ( var i = 0; i < args.length && arg < arguments.length; i++ )
if ( args[i] === undefined )
args[i] = arguments[arg++];
return fn.apply(this, args);
};
};
Define the callback like this:
callback = function(item, value) { console.log(item + value) }.partial(undefined, "myValue")
Now when you call callback('myItem'), it correctly displays "myItem myValue"

Two sets of parentheses after function call

I was looking how filters works in Angularjs and I saw that we need to send 2 sets of parentheses.
$filter('number')(number[, fractionSize])
What does it means and how do we handle it with JavaScript?
It means that the first function ($filter) returns another function and then that returned function is called immediately. For Example:
function add(x){
return function(y){
return x + y;
};
}
var addTwo = add(2);
addTwo(4) === 6; // true
add(3)(4) === 7; // true
$filter('number') returns a function that accepts two arguments, the first being required (a number) and the second one being optional (the fraction size).
It's possible to immediately call the returned function:
$filter('number')('123')
Alternatively, you may keep the returned function for future use:
var numberFilter = $filter('number');
numberFilter('123')
It is the same as this:
var func = $filter('number');
func(number[, fractionSize]);
The $filter() function returns a pointer to another function.
with ES6 or later versions you can do it that way;
const divideBoth = (x) => (y) => {
return x / y;
};
one of the reasons that makes this function type useful is when you have a react.js component that needs have callback function instead of doing it inline way(which is ()=>return value) you can do it the way we did previously. But it is not recommended to use in event callbacks because it gets execute in the first render which might cause issues sometimes

Categories