Browse files

blogged 'the dipert problem'

  • Loading branch information...
1 parent 3cd6f61 commit 15200cdc82dfcd9eccff64a9ae1920321a0be60e @twopoint718 committed Sep 3, 2012
Showing with 148 additions and 32 deletions.
  1. +74 −0 blog.html
  2. +74 −32 index.html
@@ -17,6 +17,80 @@
<div id="maincol" class="yui-b">
<h1 id="blog">Blog</h1>
<p>Here are recent entries. Page anchors are on <a href="">ISO 8601</a> dates (e.g. <em>2011-05-27</em>), so you can access the oldest entry like: <a href="blog.html#2010-11-13">blog.html#2010-11-13</a>. I’m still figuring out how to do permalinks and individual pages.</p>
+<h2 id="the-dipert-problem"><a name="2012-09-03">the dipert problem</a></h2>
+<p>Recently, <a href="">Alan Dipert</a> dropped a bomb on the twittersphere with his posing of <a href="">this question</a> (warning there are spoilers in the replies):</p>
+<p>“pop quiz: solve <a href=""><code class="url"></code></a> point-free. answer must be a function value! #clojure”</p>
+<p>In case your office has banned 4clojure for being a huge distraction, I’ll post the problem here:</p>
+<pre><code>(= 256 ((__ 2) 16),
+ ((__ 8) 2))
+(= [1 8 27 64] (map (__ 3) [1 2 3 4]))
+(= [1 2 4 8 16] (map #((__ %) 2) [0 1 2 3 4]))</code></pre>
+<p>In problem 107, your challenge is to write a function that satisfies all of these (it could be dropped in place of the <code>__</code>s above). I will let you go take a crack at solving it. Because up next is some serious spoiler action.</p>
+<p>Got your solution? I came up with this:</p>
+<pre><code>(fn [x] (fn [y] (reduce * (repeat x y))))</code></pre>
+<p>or (what I was really doing) in Haskell:</p>
+<pre><code>f :: Int -&gt; Int -&gt; Int
+f x y = foldl1 (*) (replicate x y)</code></pre>
+<p>We are doing manual exponentiation: &quot;make a list of <em>y</em>s that is <em>x</em> in length (e.g. <code>replicate 8 2 == [2, 2, 2, 2, 2, 2, 2, 2]</code>). Then you just run multiplication through the list:</p>
+<pre><code>foldl1 (*) [2,2,2,2,2,2,2,2] == 2 * 2 * 2 * ... 2 == 256</code></pre>
+<p>Now comes the “Dipert Problem.” He has told us that we have to rewrite the solution (or any solution) using so-called <em>point-free</em> style. I’m sure that there’s more to it, but essentially that means that <em>we are not allowed to mention any variables!</em> When I first heard about this style, it sounded impossible! The cool thing is that it <em>isn’t</em> and it leads to some massively simple code. Let’s try it out.</p>
+<p>I’m going to start with my solution above called <code>f</code> and then write some successive versions of it, each time, I’ll remove a variable and call it the “next” version: <code>f1</code>, <code>f2</code>, okay? Cool.</p>
+<pre><code>f, f1, f2 :: Int -&gt; Int -&gt; Int
+f x y = foldl1 (*) (replicate x y)</code></pre>
+<p>For the first transformation, we need to get rid of the <code>y</code> that’s hanging off the end of both sides of our equation. We’ll need to juggle the innards a bit because here is what the types look like so far:</p>
+<pre><code>foldl1 (*) :: [Int] -&gt; Int
+replicate x y :: Int -&gt; a -&gt; [a]</code></pre>
+<p><code>replicate</code> takes two arguments and then produces a list that the <code>foldl1 (*)</code> wants to consume. The trouble is, and what tripped me up a bunch, is that I can’t just do this:</p>
+<pre><code>foldl1 (*) . replicate</code></pre>
+<p>Wah, wah (sad trombone). GHCI tells me:</p>
+<pre><code>Expected type: Int -&gt; [c0]
+ Actual type: Int -&gt; a0 -&gt; [a0]</code></pre>
+<p>Okay, that makes sense, for the fold and replicate to “line up” for composition, replicate has to take one argument then produce a list. The crux is that composition (the “dot” or period in the code) only works for single-argument-functons:</p>
+<pre><code>(.) :: (b -&gt; c) -&gt; (a -&gt; b) -&gt; a -&gt; c</code></pre>
+<p>This is a little pipeline, but reversed because that’s how mathematics does it. It says “the right-side function takes an <em>a</em> and gives a <em>b</em>, and the left-side function expects a <em>b</em> and gives a <em>c</em>; now you can stitch them together and have a function that <em>skips</em> the <em>b</em> and takes you right from <em>a</em> to <em>c</em>.” But we have a function that looks like:</p>
+<pre><code>(a -&gt; b -&gt; c)</code></pre>
+<p>on the right-hand side; it won’t work. how to we convert a <code>(a -&gt; b -&gt; c)</code> to a <code>(a -&gt; (b -&gt; c))</code>? This way:</p>
+f x y = foldl1 (*) ((replicate x) y)
+f x y = (foldl1 (*) . (replicate x)) y
+f1 x = foldl1 (*) . (replicate x)</code></pre>
+<p><em>Note:</em> the first two lines are commented in case you are cut-n-pasting along. The first line just puts parenthesis in where they really are in haskell. Each time you see a function of two arguments, it <em>is really</em> a function which takes one argument and returns a function that expects the second argument! This weird but remarkable fact of haskell is called <a href="">currying</a>.</p>
+<p>Now, on to the second line, we see that we have the right types! (I am cheating a bit on types, if you like, you can define <code>rep</code> which <em>just</em> uses <code>Int</code>s)</p>
+<pre><code>replicate x :: Int -&gt; [Int] -- cheating: where &#39;x&#39; is a specific int
+foldl1 (*) :: [Int] -&gt; Int
+foldl1 (*) . replicate x :: Int -&gt; Int</code></pre>
+<p>And that brings us to <code>f1</code>! We used grouping and composition to move the <code>y</code> outside the computation and then we dropped it from both sides.</p>
+<p>Next we’ll tackle the x:</p>
+f x = (foldl1 (*) .) (replicate x)
+f x = ((foldl1 (*) .) . replicate) x
+f2 = (foldl1 (*) .) . replicate</code></pre>
+<p>It may look different, but the same thing is going on. We can group the composition with the fold without changing anything. This is just like doing:</p>
+<pre><code>3 + 4 == (3 +) 4</code></pre>
+<p>Next we do that same trick again where we can now compose the inner functions because the types line up (again, I’m simplifying types a bit):</p>
+<pre><code>((foldl1 (*) .) .) :: (a -&gt; b -&gt; [c]) -&gt; a -&gt; b -&gt; c</code></pre>
+<p>it looks a bit hairy, but in our case, it is just what we want! If I fill in the actual types we’ll be using, it becomes clearer:</p>
+<pre><code>((foldl1 (*) .) .) :: (Int -&gt; Int -&gt; [Int]) -&gt; Int -&gt; Int -&gt; Int</code></pre>
+<p>Booyah! This contraption takes a <em>function</em> of two <code>Ints</code> that produces a list of ints, <code>[Int]</code>. Well, that’s just what <code>replicate</code> is! So if we then feed in replicate:</p>
+<pre><code>(foldl1 (*) .) . replicate :: Int -&gt; Int -&gt; Int</code></pre>
+<p>And that’s it, we have a point-free function that takes two <code>Int</code>s and returns an <code>Int</code>. And so that’s our last, and final function:</p>
+<pre><code>f2 = (foldl1 (*) .) . replicate</code></pre>
+<p>In general, and I don’t know a term for this, but the operation of successive function composition lets compose higher and higher arity functions together. Here’s a dumb example using my little point-free <code>succ</code> function:</p>
+<pre><code>g :: Int -&gt; Int
+g = (+1)
+(g .) :: (a -&gt; Int) -&gt; a -&gt; Int
+(g .) .) :: (a -&gt; b -&gt; Int) -&gt; a -&gt; b -&gt; Int
+(g .) .) .) :: (a -&gt; b -&gt; c -&gt; Int) -&gt; a -&gt; b -&gt; c -&gt; Int</code></pre>
+<p>Clear pattern. I kinda think of this as saying something like “please give me a function which <em>eventually</em> promises to give me what I want.” The <em>eventually</em> part is essentially “after you’ve collected all the stuff you need.” It would be trivially satisfied by some function that ignores its args and returns a constant:</p>
+<pre><code>(((g .) .) .) (\x y z -&gt; 1) 4 5 6 == 2</code></pre>
+<p>Remembering that <code>g</code> just increments, the x y z are <em>totally ignored</em>. The function supplied to the multiply-composed <code>g</code> is like some kind of integer “pre-processor”; the <em>x</em>, <em>y</em> and <em>z</em> can be whatever you need to do to figure out how to give g an integer. Or at least that’s how I’m thinking of it.</p>
+<p>I had a lot of fun trying to figure this out!</p>
<h2 id="my-transparent-web-talk"><a name="2012-08-22">my “transparent web” talk</a></h2>
<iframe src="" width="427" height="356" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen> </iframe> <div style="margin-bottom:5px">
Oops, something went wrong.

0 comments on commit 15200cd

Please sign in to comment.