<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
		>
<channel>
	<title>Comments on: Memoizing polymorphic functions &#8211; part two</title>
	<atom:link href="http://conal.net/blog/posts/memoizing-polymorphic-functions-part-two/feed/" rel="self" type="application/rss+xml" />
	<link>http://conal.net/blog/posts/memoizing-polymorphic-functions-part-two/</link>
	<description>Inspirations &#38; experiments, mainly about denotational programming in Haskell</description>
	<lastBuildDate>Tue, 09 Mar 2010 23:08:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
		<item>
		<title>By: Neel Krishnaswami</title>
		<link>http://conal.net/blog/posts/memoizing-polymorphic-functions-part-two/comment-page-1/#comment-22648</link>
		<dc:creator>Neel Krishnaswami</dc:creator>
		<pubDate>Thu, 18 Jun 2009 19:30:17 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=89#comment-22648</guid>
		<description>&lt;p&gt;Hi Conal, I don&#039;t know if this is enough for your purpose, but there&#039;s a beautiful trick I learned from Janis Voigtlander&#039;s 2009 POPL paper &quot;Bidirectionalization for Free&quot;. The idea is to to exploit parametricity -- if you have a function that operates over lists parametrically, you can find out what it does on &lt;em&gt;any&lt;/em&gt; argument by passing it a list of unique integers, and looking at how it permutes those integers.&lt;/p&gt;

&lt;p&gt;The same trick ought to work for memoization. If we want to write a function&lt;/p&gt;

&lt;pre&gt;
     memo&#039; : (all a. k a -&gt; v a) -&gt; (all a. k a -&gt; v a)`
&lt;/pre&gt;

&lt;p&gt;then it&#039;s sufficient if we can write the memo function for the Int case. More abstactly, we can do this if k and v are functors, and k also has a way to distribute over the state monad (that is, we want a function &lt;code&gt;seq : (k (state a)) -&gt; (state (k a))&lt;/code&gt;. Then, we want to write something like (I&#039;ll use a mutant hybrid ML/Haskell syntax here):&lt;/p&gt;

&lt;pre&gt;
type state r a = (Int, Int -&gt; r) -&gt; ((Int, Int -&gt; r), a)

eat : r -&gt; state r int 
eat r (size, mapping) = ((size+1, \n. if n = size then r else mapping n), size)

run : state r a -&gt; int -&gt; r -&gt; ((int, int -&gt; r), a)
run state initsize initmap = state (initsize, initmap)

seq : k (state r a) -&gt; state r (k a)
seq blah = whatever

memo&#039; (f : all a. k a -&gt; v a) = 
  let table : ref (k int -&gt; option (v int)) =  ref (\x. Nothing)   -- allocate a table
  let memofun x : k b = 
    let leaves : k (state b int) = map_k eat x 
    let traversal : state b (k int) = seq leaves 
    let ((size, indices), shape) = run traversal 0 (\x. bot)
    case !table shape of 
      Just result_shape -&gt; fmap indices result_shape
    &#124; Nothing -&gt; let result_shape = f shape in 
                 begin
                    table := update table shape result_shape;  -- imperatively update the memo table
                    return (fmap indices result_shape)
                 end
 
&lt;/pre&gt;

&lt;p&gt;The idea is that we use map and seq to construct an action that will walk over the key, replacing each polymorphic
value with a unique integer index. Map crawls over the term, and we stick a little command in a state monad to eat
the value there. Then, we use &lt;code&gt;seq&lt;/code&gt; to sequence all those terms, ensuring we a) get unique indices at all the leaves,
and b) we can get a mapping from those indices back to the original values.&lt;/p&gt;

&lt;p&gt;Then, we can use memoize the int version of the value, and its result. Given an integer-valued result, we can use the mapping from indices to values to put back the correct values. So v needs to be a functor, and k needs to be a functor with a sequencing distribution property -- the traversable stuff ought to be the right general property to ask for.&lt;/p&gt;
</description>
		<content:encoded><![CDATA[<p>Hi Conal, I don&#8217;t know if this is enough for your purpose, but there&#8217;s a beautiful trick I learned from Janis Voigtlander&#8217;s 2009 POPL paper &#8220;Bidirectionalization for Free&#8221;. The idea is to to exploit parametricity &#8212; if you have a function that operates over lists parametrically, you can find out what it does on <em>any</em> argument by passing it a list of unique integers, and looking at how it permutes those integers.</p>

<p>The same trick ought to work for memoization. If we want to write a function</p>

<pre>
     memo' : (all a. k a -&gt; v a) -&gt; (all a. k a -&gt; v a)`
</pre>

<p>then it&#8217;s sufficient if we can write the memo function for the Int case. More abstactly, we can do this if k and v are functors, and k also has a way to distribute over the state monad (that is, we want a function <code>seq : (k (state a)) -&gt; (state (k a))</code>. Then, we want to write something like (I&#8217;ll use a mutant hybrid ML/Haskell syntax here):</p>

<pre>
type state r a = (Int, Int -&gt; r) -&gt; ((Int, Int -&gt; r), a)

eat : r -&gt; state r int 
eat r (size, mapping) = ((size+1, \n. if n = size then r else mapping n), size)

run : state r a -&gt; int -&gt; r -&gt; ((int, int -&gt; r), a)
run state initsize initmap = state (initsize, initmap)

seq : k (state r a) -&gt; state r (k a)
seq blah = whatever

memo' (f : all a. k a -&gt; v a) = 
  let table : ref (k int -&gt; option (v int)) =  ref (\x. Nothing)   -- allocate a table
  let memofun x : k b = 
    let leaves : k (state b int) = map_k eat x 
    let traversal : state b (k int) = seq leaves 
    let ((size, indices), shape) = run traversal 0 (\x. bot)
    case !table shape of 
      Just result_shape -&gt; fmap indices result_shape
    | Nothing -&gt; let result_shape = f shape in 
                 begin
                    table := update table shape result_shape;  -- imperatively update the memo table
                    return (fmap indices result_shape)
                 end
 
</pre>

<p>The idea is that we use map and seq to construct an action that will walk over the key, replacing each polymorphic
value with a unique integer index. Map crawls over the term, and we stick a little command in a state monad to eat
the value there. Then, we use <code>seq</code> to sequence all those terms, ensuring we a) get unique indices at all the leaves,
and b) we can get a mapping from those indices back to the original values.</p>

<p>Then, we can use memoize the int version of the value, and its result. Given an integer-valued result, we can use the mapping from indices to values to put back the correct values. So v needs to be a functor, and k needs to be a functor with a sequencing distribution property &#8212; the traversable stuff ought to be the right general property to ask for.</p>]]></content:encoded>
	</item>
</channel>
</rss>
