Posts tagged "Haskell"urn:www-greghendershott-com:Haskell2014-11-03T15:51:21ZHands-on with Haskell week 1urn:www-greghendershott-com:-2014-11-hands-on-with-haskell.html2014-11-03T15:51:21Z2014-11-03T15:51:21ZGreg Hendershott
<div>
<article>
<header>
<h1>Hands-on with Haskell week 1</h1>
<p class="date-and-tags">
<time datetime="2014-11-03" pubdate="true">2014-11-03</time> :: <span class="tags"><a href="/tags/Haskell.html">Haskell</a>, <a href="/tags/Hacker-School.html">Hacker School</a></span></p></header>
<p>Last week I decided to pivot from Clojure hands-on to Haskell hands-on.</p><!-- more-->
<h1 id="rewiring-brain-from-lisp-to-haskell">Rewiring brain from Lisp to Haskell</h1>
<p>Prior to this, I had spent some time working through examples in <a href="http://learnyouahaskell.com/">Learn You a Haskell</a> and armchair browsing <a href="http://book.realworldhaskell.org/">Real World Haskell</a>. Also I’d spent some time using Typed Racket and was already sold on the benefits of having a “real” type system, especially for certain sorts of programs. So this wasn’t starting from scratch. However I soon discovered there were some things about Haskell that I’d forgotten and needed to re-learn. Also I suffered from a Lisp brain configuration.</p>
<h2 id="sections">Sections</h2>
<p>One example was sections. On Zulip I saw a code fragment like this:</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="nf">primes</span> <span class="ow">=</span> <span class="mi">2</span> <span class="kt">:</span> <span class="p">[</span><span class="n">i</span> <span class="o">|</span> <span class="n">i</span> <span class="ow"><-</span> <span class="p">[</span><span class="mi">3</span><span class="o">..</span><span class="p">],</span> <span class="n">and</span> <span class="p">[</span><span class="n">rem</span> <span class="n">i</span> <span class="n">p</span> <span class="o">></span> <span class="mi">0</span> <span class="o">|</span> <span class="n">p</span> <span class="ow"><-</span> <span class="n">takeWhile</span> <span class="p">((</span><span class="o"><=</span><span class="n">i</span><span class="p">)</span><span class="o">.</span><span class="p">(</span><span class="o">^</span><span class="mi">2</span><span class="p">))</span> <span class="n">primes</span><span class="p">]]</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>With the comment that the <code>(<= i)</code> was equivalent to <code>(\j -> (j <= i))</code>.</p>
<p>Wait. Why not <code>(\j -> (i <= j))</code>?</p>
<p>The answer is that a section behaves differently when used with an infix operator. The argument is applied on the missing side. In other words <code>(/ 10)</code> and <code>(10 /)</code> are different.</p>
<p>So <code>(< 1) 2</code> is <code>False</code> but <code>(1 <) 2</code> is <code>True</code>. And <code>(compare 1) 2</code> is <code>True</code>.</p>
<p>In Haskell it’s <em>not</em> the case that <code>(< 1)</code> is <code>1</code> partially applied to the <code><</code> function, waiting to take a “right” argument.<sup><a href="#hands-on-with-haskell-footnote-1-definition" name="hands-on-with-haskell-footnote-1-return">1</a></sup></p>
<h2 id="commas">Commas</h2>
<p>In working through <a href="http://learnyouahaskell.com/">Learn You a Haskell</a> I wanted to make an example input to try with <code>nub</code>. I wanted a long list containing duplicates, that I didn’t have to type in by hand. To do so I wanted to do a Racket <code>flatten</code> of a Haskell <code>replicate</code> of a short list. It seemed like <code>foldr1</code> with <code>++</code> would be the way to do the <code>flatten</code>. So I tried something like:</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1
2
3
4
5
6
7
8</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span><span class="p">])</span>
<span class="o"><</span><span class="n">interactive</span><span class="o">>:</span><span class="mi">107</span><span class="kt">:</span><span class="mi">1</span><span class="kt">:</span>
<span class="kt">Couldn't</span> <span class="n">match</span> <span class="n">expected</span> <span class="kr">type</span> <span class="p">`[</span><span class="n">a0</span><span class="p">]</span><span class="sc">'</span>
<span class="n">with</span> <span class="n">actual</span> <span class="kr">type</span> <span class="p">`(</span><span class="n">a1</span> <span class="ow">-></span> <span class="n">a1</span> <span class="ow">-></span> <span class="n">a1</span><span class="p">)</span> <span class="ow">-></span> <span class="p">[</span><span class="n">a1</span><span class="p">]</span> <span class="ow">-></span> <span class="n">a1'</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">first</span> <span class="n">argument</span> <span class="kr">of</span> <span class="p">`(</span><span class="o">++</span><span class="p">)</span><span class="sc">'</span><span class="err">, namely `foldr</span><span class="sc">1'</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">expression</span><span class="kt">:</span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span><span class="p">])</span>
<span class="kt">In</span> <span class="n">an</span> <span class="n">equation</span> <span class="n">for</span> <span class="p">`</span><span class="n">it'</span><span class="kt">:</span> <span class="n">it</span> <span class="ow">=</span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span> <span class="mi">5</span><span class="p">])</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>Oops. Let’s try something simpler, first.</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1
2
3
4
5
6
7
8</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">[[</span><span class="mi">1</span><span class="p">][</span><span class="mi">2</span><span class="p">]]</span>
<span class="o"><</span><span class="n">interactive</span><span class="o">>:</span><span class="mi">245</span><span class="kt">:</span><span class="mi">1</span><span class="kt">:</span>
<span class="kt">Couldn't</span> <span class="n">match</span> <span class="n">expected</span> <span class="kr">type</span> <span class="p">`[</span><span class="n">a0</span><span class="p">]</span><span class="sc">'</span>
<span class="n">with</span> <span class="n">actual</span> <span class="kr">type</span> <span class="p">`(</span><span class="n">a1</span> <span class="ow">-></span> <span class="n">a1</span> <span class="ow">-></span> <span class="n">a1</span><span class="p">)</span> <span class="ow">-></span> <span class="p">[</span><span class="n">a1</span><span class="p">]</span> <span class="ow">-></span> <span class="n">a1'</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">first</span> <span class="n">argument</span> <span class="kr">of</span> <span class="p">`(</span><span class="o">++</span><span class="p">)</span><span class="sc">'</span><span class="err">, namely `foldr</span><span class="sc">1'</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">expression</span><span class="kt">:</span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">[[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
<span class="kt">In</span> <span class="n">an</span> <span class="n">equation</span> <span class="n">for</span> <span class="p">`</span><span class="n">it'</span><span class="kt">:</span> <span class="n">it</span> <span class="ow">=</span> <span class="n">foldr1</span> <span class="o">++</span> <span class="p">[[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>Huh. Oh right. The <code>++</code> is infix. Needs to go in parens. Try again:</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1
2
3
4
5
6
7
8</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">foldr1</span> <span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="p">[[</span><span class="mi">1</span><span class="p">][</span><span class="mi">2</span><span class="p">]]</span>
<span class="o"><</span><span class="n">interactive</span><span class="o">>:</span><span class="mi">246</span><span class="kt">:</span><span class="mi">14</span><span class="kt">:</span>
<span class="kt">The</span> <span class="n">function</span> <span class="p">`[</span><span class="mi">1</span><span class="p">]</span><span class="sc">'</span><span class="err"> is applied to one argument,</span>
<span class="n">but</span> <span class="n">its</span> <span class="kr">type</span> <span class="p">`[</span><span class="n">t0</span><span class="p">]</span><span class="sc">'</span><span class="err"> has none</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">expression</span><span class="kt">:</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">second</span> <span class="n">argument</span> <span class="kr">of</span> <span class="p">`</span><span class="n">foldr1'</span><span class="p">,</span> <span class="n">namely</span> <span class="p">`[[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span><span class="p">]]</span><span class="sc">'</span>
<span class="kt">In</span> <span class="n">the</span> <span class="n">expression</span><span class="kt">:</span> <span class="n">foldr1</span> <span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="p">[[</span><span class="mi">1</span><span class="p">]</span> <span class="p">[</span><span class="mi">2</span><span class="p">]]</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>Bzzzt. Tried to decipher the error message. Finally remembered, dang, I need to separate list items with commas:</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1
2</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">foldr1</span> <span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="p">[[</span><span class="mi">1</span><span class="p">],[</span><span class="mi">2</span><span class="p">]]</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>OK. And building back up again to what I’d wanted originally:</p>
<div class="brush: hs">
<table class="sourcetable">
<tbody>
<tr>
<td class="linenos">
<div class="linenodiv">
<pre>1
2
3
4
5
6</pre></div></td>
<td class="code">
<div class="source">
<pre><span></span><span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
<span class="p">[[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">],[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]]</span>
<span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">foldr1</span> <span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">])</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
<span class="o">*</span><span class="kt">Main</span><span class="o">></span> <span class="n">nub</span> <span class="o">$</span> <span class="n">foldr1</span> <span class="p">(</span><span class="o">++</span><span class="p">)</span> <span class="p">(</span><span class="n">replicate</span> <span class="mi">5</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">])</span>
<span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">]</span>
</pre></div>
</td></tr></tbody></table>
</div>
<p>In Lisps I’ve grown accustomed to — and really love — being able to separate list items with whitespace. Needing to use commas feels a bit weird. Also it’s a bit weird that you only use them for things like lists and tuples, but not in function applications. Oh well.</p>
<h2 id="other-tiny-things">Other tiny things</h2>
<ul>
<li>
<p>I keep making the mistake of typing <code>data MyType = _</code> instead of <code>data MyType = MyType _</code>.</p></li>
<li>
<p>Racket <code>struct</code>s define accessor functions prefixed with the name of the struct. So <code>(struct person (name))</code> defines a <code>person-name</code> accessor function. In Haskell, <code>data Person = Person {name ::
String}</code> defines an accessor <code>name</code> — no prefix. Problem being, what if you have a couple types that have fields called <code>name</code>? I guess you have to do prefix the field names explicitly yourself, e.g. <code>data Person = Person {personName :: String}</code>?</p></li></ul>
<p>None of these observations are intended as a critique of Haskell. It’s an observation how the tiny things can trip you up when learning a new language. Even after a couple days, I’ve developed a sort of subconscious checklist of rookie mistakes to consider before trying to understand the Haskell error message.</p>
<h1 id="nice-things">Nice things</h1>
<ul>
<li>
<p>I like how creating a simple Haskell “project” (just for local use) is as simple as creating a <code>.hs</code> file. I also like this in Racket.</p></li>
<li>
<p>I like having an actual, mature module system with clear best practices (as in Racket).</p></li></ul>
<h1 id="my-first-hands-on-with-cabal">My first hands-on with Cabal</h1>
<p>I used Cabal for the first time, to install Pandoc. This took… awhile. Finally I got a weird version error:</p>
<pre><code>Configuring pandoc-1.13.1...
setup: At least the following dependencies are missing:
http-client >=0.3.2 && <0.4 && ==0.4.2.2
Updating documentation index /Users/greg/Library/Haskell/doc/index.html
cabal: Error: some packages failed to install:
pandoc-1.13.1 failed during the configure step. The exception was:
ExitFailure 1</code></pre>
<p>After puzzling this over for awhile, and reading up on Cabal versioning, I didn’t have any great ideas. Finally I decided to try running <code>cabal install pandoc</code> a second time. And this time, it worked. Shrug. Onward.</p>
<h1 id="porting-wffi-to-haskell">Porting wffi to Haskell</h1>
<p>So after some “warm-up” I decided to dive in and try to port wffi to Haskell. This turned out to be a good-sized project when I was hands-on with Clojure — not too small, not too big. Implementing it requires parsing markdown, parsing HTTP request templates, making HTTP requests, using higher-order functions, and so on.</p>
<p>I forged ahead and got the wffi port of Haskell working to the point that I could successfully make a request to <a href="http://horseebooksipsum.com/">http://horseebooksipsum.com/</a>. I had a little confusion at first about how <code>HTTP.Network.simpleHTTP</code> returns <code>IO (Either String
String)</code>. Basically, I didn’t anticipate where the IO vs. pure “boundary” would need to be in my program. But once I realized that, it made sense and was easy to sort out.</p>
<p>I pushed my commits to a GitHub public <a href="https://github.com/greghendershott/haskell-wffi">repo</a>, even though I’m sure the code smells pretty badly. My normal instinct is to spend more time with code — beyond the “it’s amazing that the dancing bear dances at all” stage — before pushing to public. But I’m at Hacker School, this isn’t professional coding, and I shouldn’t be so cautious. In fact, by pushing early, I could get some feedback.</p>
<h2 id="surprisingly-easy">Surprisingly easy</h2>
<p>I was surprised by how quickly the port to Haskell went, compared to the port to Clojure. I would have guessed the opposite, because Clojure seems like it would be “closer to” Racket. I think there are two reasons why it was faster.</p>
<p>One is that I hadn’t worked on wffi for a year, so part of the Clojure port was actually reminding myself how things worked. In other words I’ve been “practicing” porting wffi, and the Haskell port got the benefit of that.</p>
<p>But also, I simply found Haskell easier to use than I expected. Sure, I frequently alternated between 10 minutes of smooth sailing and 5 minutes of trying to decipher a type error message. However, this felt different from being stalled on a Clojure build/environment/package issue. The Haskell type error messages felt like they turned out to be useful information about my reasoning about my program. Resolving them was sometimes a matter of fixing a simple mistake. Sometimes it entailed fixing a problem with my thinking and my design.<sup><a href="#hands-on-with-haskell-footnote-2-definition" name="hands-on-with-haskell-footnote-2-return">2</a></sup></p>
<p>My early days with Haskell have been more satisfying than those with Clojure. Whether that continues remains to be seen. So far so good.</p>
<div class="footnotes">
<ol>
<li id="hands-on-with-haskell-footnote-1-definition" class="footnote-definition">
<p>It’s also not the case in Racket or Clojure. You’d have to say <code>(curry < 1)</code> or <code>(partial < 1)</code>. But <em>if</em> those languages did automatic partial application, it would look like <code>(< 1)</code>. At least that’s what my Lisp brain misunderstood at first. <a href="#hands-on-with-haskell-footnote-1-return">↩</a></p></li>
<li id="hands-on-with-haskell-footnote-2-definition" class="footnote-definition">
<p>This is an experience I also had with Typed Racket. <a href="#hands-on-with-haskell-footnote-2-return">↩</a></p></li></ol></div>
<footer></footer></article></div>