<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DZone Snippets: memoization code</title>
    <link>http://snippets.dzone.com/posts</link>
    <pubDate>Thu, 24 Jul 2008 06:46:26 GMT</pubDate>
    <description>DZone Snippets: memoization code</description>
    <item>
      <title>Memoizing functions in JavaScript</title>
      <link>http://snippets.dzone.com/posts/show/488</link>
      <description>Here's something I knocked together a fortnight ago because I wanted to see if I could produce Perl's Memoize.pm in JavaScript.&lt;br /&gt;&lt;br /&gt;Memoization is a method of increasing the speed of slow referentially transparent functions by caching their arguments and results. This trades a marginal amount of memory space for a potentially huge gain in speed.&lt;br /&gt;&lt;br /&gt;Take the canonical definition of the fibonacci sequence, for instance:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;function fib(n) {&lt;br /&gt;    if (n &lt; 2) {&lt;br /&gt;        return n;&lt;br /&gt;    }&lt;br /&gt;    return fib(n - 1) + fib(n - 2);&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;As you can guess, this quickly becomes quite slow once you start using numbers greater than around 20. Once you're dealing with numbers in the mid-thirties range, it cripples the computer.&lt;br /&gt;&lt;br /&gt;The solution is to memoize the function. You can either do it by hand:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;var iterMemoFib = (function() {&lt;br /&gt;    var cache = [1, 1];&lt;br /&gt;    var fib = function(n) {&lt;br /&gt;        if (n &gt;= cache.length) {&lt;br /&gt;            for (var i = cache.length; i &lt;= n; i++) {&lt;br /&gt;                cache[i] = cache[i - 2] + cache[i - 1];&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return cache[n];&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return fib;&lt;br /&gt;})();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Which is a wee bit of a pain and not exactly readable; or get the computer to do it for you:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;fib = fib.memoize();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Due to technical (browser security) constraints, the arguments for memoized functions can only be arrays or scalar values. No objects.&lt;br /&gt;&lt;br /&gt;The code extends the Function object to add the memoization functionality. If the function is a method, then you can pass the object into memoize().&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Function.prototype.memoize = function() {&lt;br /&gt;    var pad  = {};&lt;br /&gt;    var self = this;&lt;br /&gt;    var obj  = arguments.length &gt; 0 ? arguments[i] : null;&lt;br /&gt;&lt;br /&gt;    var memoizedFn = function() {&lt;br /&gt;        // Copy the arguments object into an array: allows it to&lt;br /&gt;        // be used as a cache key.&lt;br /&gt;        var args = [];&lt;br /&gt;        for (var i = 0; i &lt; arguments.length; i++) {&lt;br /&gt;            args[i] = arguments[i];&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        // Evaluate the memoized function if it hasn't been&lt;br /&gt;        // evaluated with these arguments before.&lt;br /&gt;        if (!(args in pad)) {&lt;br /&gt;            pad[args] = self.apply(obj, arguments);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        return pad[args];&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    memoizedFn.unmemoize = function() {&lt;br /&gt;        return self;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    return memoizedFn;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Function.prototype.unmemoize = function() {&lt;br /&gt;    alert("Attempt to unmemoize an unmemoized function.");&lt;br /&gt;    return null;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;</description>
      <pubDate>Fri, 22 Jul 2005 05:35:49 GMT</pubDate>
      <guid>http://snippets.dzone.com/posts/show/488</guid>
      <author>keith (Keith Gaughan)</author>
    </item>
  </channel>
</rss>
