mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
3661 lines
544 KiB
HTML
3661 lines
544 KiB
HTML
<!DOCTYPE html>
|
||
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="generator" content="pandoc" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||
<title>Haskell Mooc, part 2</title>
|
||
<style type="text/css">
|
||
code{white-space: pre-wrap;}
|
||
span.smallcaps{font-variant: small-caps;}
|
||
span.underline{text-decoration: underline;}
|
||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||
</style>
|
||
<style type="text/css">
|
||
a.sourceLine { display: inline-block; line-height: 1.25; }
|
||
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
|
||
a.sourceLine:empty { height: 1.2em; position: absolute; }
|
||
.sourceCode { overflow: visible; }
|
||
code.sourceCode { white-space: pre; position: relative; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
code.sourceCode { white-space: pre-wrap; }
|
||
a.sourceLine { text-indent: -1em; padding-left: 1em; }
|
||
}
|
||
pre.numberSource a.sourceLine
|
||
{ position: relative; }
|
||
pre.numberSource a.sourceLine:empty
|
||
{ position: absolute; }
|
||
pre.numberSource a.sourceLine::before
|
||
{ content: attr(data-line-number);
|
||
position: absolute; left: -5em; text-align: right; vertical-align: baseline;
|
||
border: none; pointer-events: all;
|
||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||
-khtml-user-select: none; -moz-user-select: none;
|
||
-ms-user-select: none; user-select: none;
|
||
padding: 0 4px; width: 4em;
|
||
color: #aaaaaa;
|
||
}
|
||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||
div.sourceCode
|
||
{ }
|
||
@media screen {
|
||
a.sourceLine::before { text-decoration: underline; }
|
||
}
|
||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||
code span.at { color: #7d9029; } /* Attribute */
|
||
code span.bn { color: #40a070; } /* BaseN */
|
||
code span.bu { } /* BuiltIn */
|
||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||
code span.ch { color: #4070a0; } /* Char */
|
||
code span.cn { color: #880000; } /* Constant */
|
||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||
code span.dt { color: #902000; } /* DataType */
|
||
code span.dv { color: #40a070; } /* DecVal */
|
||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||
code span.ex { } /* Extension */
|
||
code span.fl { color: #40a070; } /* Float */
|
||
code span.fu { color: #06287e; } /* Function */
|
||
code span.im { } /* Import */
|
||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||
code span.op { color: #666666; } /* Operator */
|
||
code span.ot { color: #007020; } /* Other */
|
||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||
code span.ss { color: #bb6688; } /* SpecialString */
|
||
code span.st { color: #4070a0; } /* String */
|
||
code span.va { color: #19177c; } /* Variable */
|
||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||
</style>
|
||
<link rel="stylesheet" href="./style.css">
|
||
<!--[if lt IE 9]>
|
||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
||
<![endif]-->
|
||
</head>
|
||
<body>
|
||
<div id="everything">
|
||
<nav id="TOC">
|
||
<ul>
|
||
<li><a href="#lecture-9-recap-of-part-1"><span class="toc-section-number">9</span> Lecture 9: Recap of Part 1</a><ul>
|
||
<li><a href="#types"><span class="toc-section-number">9.1</span> Types</a></li>
|
||
<li><a href="#functions"><span class="toc-section-number">9.2</span> Functions</a></li>
|
||
<li><a href="#functional-programming"><span class="toc-section-number">9.3</span> Functional Programming</a></li>
|
||
<li><a href="#recursion"><span class="toc-section-number">9.4</span> Recursion</a></li>
|
||
<li><a href="#type-classes"><span class="toc-section-number">9.5</span> Type Classes</a></li>
|
||
<li><a href="#quiz"><span class="toc-section-number">9.6</span> Quiz</a></li>
|
||
<li><a href="#working-on-the-exercises"><span class="toc-section-number">9.7</span> Working on the Exercises</a></li>
|
||
<li><a href="#exercises"><span class="toc-section-number">9.8</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-10-reductionism"><span class="toc-section-number">10</span> Lecture 10: Reductionism</a><ul>
|
||
<li><a href="#laziness-purity"><span class="toc-section-number">10.1</span> Laziness & Purity</a></li>
|
||
<li><a href="#equational-reasoning"><span class="toc-section-number">10.2</span> Equational Reasoning</a></li>
|
||
<li><a href="#infinite-lists"><span class="toc-section-number">10.3</span> Infinite Lists</a></li>
|
||
<li><a href="#how-does-haskell-work"><span class="toc-section-number">10.4</span> How does Haskell Work?</a></li>
|
||
<li><a href="#working-with-infinite-lists"><span class="toc-section-number">10.5</span> Working with Infinite Lists</a></li>
|
||
<li><a href="#interlude-adding-strictness"><span class="toc-section-number">10.6</span> Interlude: Adding Strictness</a></li>
|
||
<li><a href="#newtype-declarations"><span class="toc-section-number">10.7</span> Newtype Declarations</a></li>
|
||
<li><a href="#something-fun-tying-the-knot"><span class="toc-section-number">10.8</span> Something Fun: Tying the Knot</a></li>
|
||
<li><a href="#something-fun-debug.trace"><span class="toc-section-number">10.9</span> Something Fun: Debug.Trace</a></li>
|
||
<li><a href="#quiz-1"><span class="toc-section-number">10.10</span> Quiz</a></li>
|
||
<li><a href="#exercises-1"><span class="toc-section-number">10.11</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-11-realworld---arealworld"><span class="toc-section-number">11</span> Lecture 11: <code>RealWorld -> (a,RealWorld)</code></a><ul>
|
||
<li><a href="#contents"><span class="toc-section-number">11.1</span> Contents</a></li>
|
||
<li><a href="#youve-been-fooled"><span class="toc-section-number">11.2</span> You’ve Been Fooled!</a></li>
|
||
<li><a href="#the-subtle-return"><span class="toc-section-number">11.3</span> The Subtle <code>return</code></a></li>
|
||
<li><a href="#do-and-types"><span class="toc-section-number">11.4</span> <code>do</code> and Types</a></li>
|
||
<li><a href="#control-structures"><span class="toc-section-number">11.5</span> Control Structures</a></li>
|
||
<li><a href="#a-word-about-do-and-indentation"><span class="toc-section-number">11.6</span> A Word About <code>do</code> and Indentation</a></li>
|
||
<li><a href="#lets-write-a-program"><span class="toc-section-number">11.7</span> Let’s Write a Program</a></li>
|
||
<li><a href="#what-does-it-all-mean"><span class="toc-section-number">11.8</span> What Does It All Mean?</a></li>
|
||
<li><a href="#one-more-thing-ioref"><span class="toc-section-number">11.9</span> One More Thing: IORef</a></li>
|
||
<li><a href="#summary-of-io"><span class="toc-section-number">11.10</span> Summary of IO</a></li>
|
||
<li><a href="#quiz-2"><span class="toc-section-number">11.11</span> Quiz</a></li>
|
||
<li><a href="#exercises-2"><span class="toc-section-number">11.12</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-12-fmap-fmap-fmap"><span class="toc-section-number">12</span> Lecture 12: fmap fmap fmap</a><ul>
|
||
<li><a href="#contents-1"><span class="toc-section-number">12.1</span> Contents</a></li>
|
||
<li><a href="#functors"><span class="toc-section-number">12.2</span> Functors</a></li>
|
||
<li><a href="#lawful-instances"><span class="toc-section-number">12.3</span> Lawful Instances</a></li>
|
||
<li><a href="#sidenote-kinds"><span class="toc-section-number">12.4</span> Sidenote: Kinds</a></li>
|
||
<li><a href="#foldable-again"><span class="toc-section-number">12.5</span> <code>Foldable</code>, Again</a></li>
|
||
<li><a href="#recap"><span class="toc-section-number">12.6</span> Recap</a></li>
|
||
<li><a href="#quiz-3"><span class="toc-section-number">12.7</span> Quiz</a></li>
|
||
<li><a href="#exercises-3"><span class="toc-section-number">12.8</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-13-a-monoid-in-the-category-of-problems"><span class="toc-section-number">13</span> Lecture 13: A Monoid in the Category of Problems</a><ul>
|
||
<li><a href="#example-1-maybes"><span class="toc-section-number">13.1</span> Example 1: Maybes</a></li>
|
||
<li><a href="#example-2-logging"><span class="toc-section-number">13.2</span> Example 2: Logging</a></li>
|
||
<li><a href="#example-3-keeping-state"><span class="toc-section-number">13.3</span> Example 3: Keeping State</a></li>
|
||
<li><a href="#finally-the-monad-type-class"><span class="toc-section-number">13.4</span> Finally: The Monad Type Class</a></li>
|
||
<li><a href="#maybe-is-a-monad"><span class="toc-section-number">13.5</span> Maybe is a Monad!</a></li>
|
||
<li><a href="#the-return-of-do"><span class="toc-section-number">13.6</span> The Return of <code>do</code></a></li>
|
||
<li><a href="#logger-is-a-monad"><span class="toc-section-number">13.7</span> Logger is a Monad!</a></li>
|
||
<li><a href="#the-state-monad"><span class="toc-section-number">13.8</span> The State Monad</a></li>
|
||
<li><a href="#the-return-of-mapm"><span class="toc-section-number">13.9</span> The Return of <code>mapM</code></a></li>
|
||
<li><a href="#monads-are-functors"><span class="toc-section-number">13.10</span> Monads are Functors</a></li>
|
||
<li><a href="#one-more-monad"><span class="toc-section-number">13.11</span> One More Monad</a></li>
|
||
<li><a href="#oh-right-io"><span class="toc-section-number">13.12</span> Oh Right, IO</a></li>
|
||
<li><a href="#monads-in-other-languages"><span class="toc-section-number">13.13</span> Monads in Other Languages</a></li>
|
||
<li><a href="#monads-wrap-up"><span class="toc-section-number">13.14</span> Monads: Wrap-up</a></li>
|
||
<li><a href="#sidenote-standard-haskell"><span class="toc-section-number">13.15</span> Sidenote: Standard Haskell</a></li>
|
||
<li><a href="#quiz-4"><span class="toc-section-number">13.16</span> Quiz</a></li>
|
||
<li><a href="#exercises-4"><span class="toc-section-number">13.17</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-14-lets-use-some-libraries"><span class="toc-section-number">14</span> Lecture 14: Let’s Use Some Libraries!</a><ul>
|
||
<li><a href="#text-and-bytestring"><span class="toc-section-number">14.1</span> <code>Text</code> and <code>ByteString</code></a></li>
|
||
<li><a href="#monads-recap"><span class="toc-section-number">14.2</span> Monads: Recap</a></li>
|
||
<li><a href="#writing-a-http-server-wai-and-warp"><span class="toc-section-number">14.3</span> Writing a HTTP Server: WAI and Warp</a></li>
|
||
<li><a href="#working-with-a-database-sqlite-simple"><span class="toc-section-number">14.4</span> Working With a Database: sqlite-simple</a></li>
|
||
<li><a href="#exercises-5"><span class="toc-section-number">14.5</span> Exercises</a></li>
|
||
</ul></li>
|
||
</ul>
|
||
</nav>
|
||
<div id="text-container">
|
||
<div id="text">
|
||
<!-- MENU -->
|
||
<header>
|
||
<h1 class="title">Haskell Mooc, part 2</h1>
|
||
</header>
|
||
<p>by Joel Kaasinen (<a href="https://nitor.com/en">Nitor</a>) and John Lång (University of Helsinki)</p>
|
||
<p><strong>Beware!</strong> This is a <em>preview</em> of part 2 of the course. It contains lectures 9 to 13. Further lectures will be added before the course is ready. The material presented here is roughly ready, and shouldn’t change too much. However, you should know that:</p>
|
||
<ul>
|
||
<li>Some exercises might change or be replaced with new exercises for the final release.</li>
|
||
<li>It won’t be possible to get study credits before the final release.</li>
|
||
<li>Feedback on this preview is much appreciated! You can help make part 2 better by testing it out. There are feedback links at the end of each section.</li>
|
||
</ul>
|
||
<p>Enjoy!</p>
|
||
<h1 id="lecture-9-recap-of-part-1"><span class="header-section-number">9</span> Lecture 9: Recap of Part 1</h1>
|
||
<p>This lecture goes over the basic parts of Haskell introduced in part 1 of the course: types, values, pattern matching, functions and recursion.</p>
|
||
<h2 id="types"><span class="header-section-number">9.1</span> Types</h2>
|
||
<p>Remember the primitive types of Haskell? Here they are:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 35%" />
|
||
<col style="width: 10%" />
|
||
<col style="width: 54%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Values</th>
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Meaning</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>True</code>, <code>False</code></td>
|
||
<td style="text-align: left;"><code>Bool</code></td>
|
||
<td style="text-align: left;">Truth values</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>0</code>, <code>1</code>, <code>20</code>, <code>-37</code>, …</td>
|
||
<td style="text-align: left;"><code>Int</code></td>
|
||
<td style="text-align: left;">Whole numbers</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>'A'</code>, <code>'a'</code>, <code>'!'</code>, …</td>
|
||
<td style="text-align: left;"><code>Char</code></td>
|
||
<td style="text-align: left;">Characters</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>""</code>, <code>"abcd"</code>, …</td>
|
||
<td style="text-align: left;"><code>String</code></td>
|
||
<td style="text-align: left;">Strings, which are actually just lists of characters, <code>[Char]</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>0.0</code>, <code>-3.2</code>, <code>12.3</code>, …</td>
|
||
<td style="text-align: left;"><code>Double</code></td>
|
||
<td style="text-align: left;">Floating-point numbers</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>()</code></td>
|
||
<td style="text-align: left;"><code>()</code></td>
|
||
<td style="text-align: left;">The so called unit type with only one value</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>It’s possible to combine these primitive types in various ways to form more complex types. Function types, tuple types and list types are examples of types that combine other types.</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 41%" />
|
||
<col style="width: 12%" />
|
||
<col style="width: 45%" />
|
||
</colgroup>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Values</th>
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Meaning</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>(1,2)</code>, <code>(True,'c')</code>, …</td>
|
||
<td style="text-align: left;"><code>(a, b)</code></td>
|
||
<td style="text-align: left;">A pair of a value of type <code>a</code> and a value of type <code>b</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>(1,2,3)</code>, <code>(1,2,'c')</code>, …</td>
|
||
<td style="text-align: left;"><code>(a, b, c)</code></td>
|
||
<td style="text-align: left;">A triple of values (of types <code>a</code>, <code>b</code> and <code>c</code>)</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[]</code>, <code>[1,2,3,4]</code>, …</td>
|
||
<td style="text-align: left;"><code>[a]</code></td>
|
||
<td style="text-align: left;">List of values of type <code>a</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>not</code>, <code>reverse</code>, <code>\x -> 1</code>, <code>\x -> x</code>, …</td>
|
||
<td style="text-align: left;"><code>a -> b</code></td>
|
||
<td style="text-align: left;">Function from type <code>a</code> to type <code>b</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>There’s one more powerful mechanism for creating more types: <em>Algebraic datatypes</em> (ADTs). Some examples include:</p>
|
||
<div class="sourceCode" id="cb1"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="co">-- Enumeration types</span></a>
|
||
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="kw">data</span> <span class="dt">Bool</span> <span class="fu">=</span> <span class="dt">True</span> <span class="fu">|</span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb1-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Color</span> <span class="fu">=</span> <span class="dt">Red</span> <span class="fu">|</span> <span class="dt">Green</span> <span class="fu">|</span> <span class="dt">Blue</span></a>
|
||
<a class="sourceLine" id="cb1-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb1-5" data-line-number="5"><span class="co">-- Record types that contain fields</span></a>
|
||
<a class="sourceLine" id="cb1-6" data-line-number="6"><span class="kw">data</span> <span class="dt">Vector2d</span> <span class="fu">=</span> <span class="dt">MakeVector</span> <span class="dt">Double</span> <span class="dt">Double</span></a>
|
||
<a class="sourceLine" id="cb1-7" data-line-number="7"><span class="kw">data</span> <span class="dt">Person</span> <span class="fu">=</span> <span class="dt">Person</span> <span class="dt">Int</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb1-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb1-9" data-line-number="9"><span class="co">-- Parameterized types. Note the type parameter `a`</span></a>
|
||
<a class="sourceLine" id="cb1-10" data-line-number="10"><span class="kw">data</span> <span class="dt">PairOf</span> a <span class="fu">=</span> <span class="dt">TwoValues</span> a a</a>
|
||
<a class="sourceLine" id="cb1-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb1-12" data-line-number="12"><span class="co">-- Recursive types</span></a>
|
||
<a class="sourceLine" id="cb1-13" data-line-number="13"><span class="kw">data</span> <span class="dt">IntList</span> <span class="fu">=</span> <span class="dt">Empty</span> <span class="fu">|</span> <span class="dt">Node</span> <span class="dt">Int</span> <span class="dt">IntList</span></a>
|
||
<a class="sourceLine" id="cb1-14" data-line-number="14"></a>
|
||
<a class="sourceLine" id="cb1-15" data-line-number="15"><span class="co">-- Complex types which combine many of these features</span></a>
|
||
<a class="sourceLine" id="cb1-16" data-line-number="16"><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="fu">=</span> <span class="dt">Nothing</span> <span class="fu">|</span> <span class="dt">Just</span> a</a>
|
||
<a class="sourceLine" id="cb1-17" data-line-number="17"><span class="kw">data</span> <span class="dt">Either</span> a b <span class="fu">=</span> <span class="dt">Left</span> a <span class="fu">|</span> <span class="dt">Right</span> b</a>
|
||
<a class="sourceLine" id="cb1-18" data-line-number="18"><span class="kw">data</span> <span class="dt">List</span> a <span class="fu">=</span> <span class="dt">Nil</span> <span class="fu">|</span> <span class="dt">Cons</span> a (<span class="dt">List</span> a) <span class="co">-- This is equivalent to the built-in [a] type</span></a>
|
||
<a class="sourceLine" id="cb1-19" data-line-number="19"><span class="kw">data</span> <span class="dt">Tree</span> a <span class="fu">=</span> <span class="dt">Leaf</span> a <span class="fu">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</a>
|
||
<a class="sourceLine" id="cb1-20" data-line-number="20"><span class="kw">data</span> <span class="dt">MultiTree</span> a <span class="fu">=</span> <span class="dt">MultiTree</span> a [<span class="dt">MultiTree</span> a] <span class="co">-- Note the list</span></a></code></pre></div>
|
||
<p>Values of these types include:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Values</th>
|
||
<th style="text-align: left;">Type</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>True</code>, <code>False</code></td>
|
||
<td style="text-align: left;"><code>Bool</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Red</code>, <code>Green</code>, <code>Blue</code></td>
|
||
<td style="text-align: left;"><code>Color</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>MakeVector 1.5 3.2</code></td>
|
||
<td style="text-align: left;"><code>Vector2d</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Person 13 "Bob"</code></td>
|
||
<td style="text-align: left;"><code>Person</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>TwoValues 1 3</code></td>
|
||
<td style="text-align: left;"><code>PairOf Int</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Empty</code>, <code>Node 3 (Node 4 Empty)</code></td>
|
||
<td style="text-align: left;"><code>IntList</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Nothing</code>, <code>Just 3</code>, <code>Just 4</code>, …</td>
|
||
<td style="text-align: left;"><code>Maybe Int</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Nothing</code>, <code>Just 'c'</code>, <code>Just 'd'</code>, …</td>
|
||
<td style="text-align: left;"><code>Maybe Char</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Left "foo"</code>, <code>Right 13</code>, …</td>
|
||
<td style="text-align: left;"><code>Either String Int</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Nil</code>, <code>Cons True Nil</code>, <code>Const True (Cons False Nil)</code> …</td>
|
||
<td style="text-align: left;"><code>List Bool</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Leaf 7</code>, <code>Node 1 (Leaf 0) (Leaf 2)</code>, …</td>
|
||
<td style="text-align: left;"><code>Tree Int</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>MultiTree 'a' [MultiTree 'b' [], MultiTree 'c' []]]</code>, …</td>
|
||
<td style="text-align: left;"><code>MultiTree Char</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>You can combine parameterized types in complex ways, for example with something like <code>Either [String->String] (Maybe String, Int)</code>.</p>
|
||
<p>The names of concrete types start with capital letters. Lowercase letters are used for <em>type variables</em> which indicate <em>parametric polymorphism</em>: functions and values that can have multiple types. Here are some examples of polymorphic function types:</p>
|
||
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb2-1" data-line-number="1">[a] <span class="ot">-></span> [a] <span class="co">-- function from list of any type, to list of the same type</span></a>
|
||
<a class="sourceLine" id="cb2-2" data-line-number="2">[a] <span class="ot">-></span> a <span class="co">-- function from list of any type, to the element type</span></a>
|
||
<a class="sourceLine" id="cb2-3" data-line-number="3">(a,b) <span class="ot">-></span> [a] <span class="co">-- function from tuple to list</span></a></code></pre></div>
|
||
<h3 id="more-about-lists"><span class="header-section-number">9.1.1</span> More About Lists</h3>
|
||
<p>List literals can be written in using the familiar <code>[x,y,z]</code> syntax. However, lists are actually built up of the list constructors <code>[]</code> and <code>(:)</code>. These constructors are also used when pattern matching lists as we’ll see next. Here are some examples of lists:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Abbreviation</th>
|
||
<th style="text-align: left;">Full list</th>
|
||
<th style="text-align: left;">Type</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[1,2,3]</code></td>
|
||
<td style="text-align: left;"><code>1:2:3:[]</code></td>
|
||
<td style="text-align: left;"><code>[Int]</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[[1],[2],[3]]</code></td>
|
||
<td style="text-align: left;"><code>(1:[]):(2:[]):(3:[]):[]</code></td>
|
||
<td style="text-align: left;"><code>[[Int]]</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>"foo"</code></td>
|
||
<td style="text-align: left;"><code>'f':'o':'o':[]</code></td>
|
||
<td style="text-align: left;"><code>[Char]</code>, also known as <code>String</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>There’s also a range syntax for lists:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Range</th>
|
||
<th style="text-align: left;">Result</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>['a' .. 'z']</code></td>
|
||
<td style="text-align: left;"><code>"abcdefghijklmnopqrstuvwxyz"</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[0 .. 9]</code></td>
|
||
<td style="text-align: left;"><code>[0,1,2,3,4,5,6,7,8,9]</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[0, 5 .. 25]</code></td>
|
||
<td style="text-align: left;"><code>[0,5,10,15,20,25]</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[min .. max]</code></td>
|
||
<td style="text-align: left;">everything from <code>min</code> to <code>max</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[9 .. 3]</code></td>
|
||
<td style="text-align: left;"><code>[]</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[max, max-1 .. min]</code></td>
|
||
<td style="text-align: left;">everything from <code>max</code> to <code>min</code> in decreasing order</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[9,8 .. 3]</code></td>
|
||
<td style="text-align: left;"><code>[9,8,7,6,5,4,3]</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p><em>List comprehensions</em> are another way for create lists:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Comprehension</th>
|
||
<th style="text-align: left;">Result</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[x^3 | x <- [1..3]]</code></td>
|
||
<td style="text-align: left;"><code>[1,8,27]</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[x^2 + y^2 | x <- [1..3], y <- [1..2]]</code></td>
|
||
<td style="text-align: left;"><code>[2,5,5,8,10,13]</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>[y | x <- [1..10], let y = x^2, even x, y<50]</code></td>
|
||
<td style="text-align: left;"><code>[4,16,36]</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>[c | c <- "Hello, World!", elem c ['a'..'z']]</code></td>
|
||
<td style="text-align: left;"><code>"elloorld"</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>In general, <code>[f x | x <- xs, p x]</code> is the same as <code>map f (filter p xs)</code>. Also, <code>[y | x <- xs, let y = f x]</code> is the same as <code>[f x | x <- xs]</code>. Any combination of <code><-</code>, <code>let</code> and <code>[f x | ...]</code> is possible.</p>
|
||
<h2 id="functions"><span class="header-section-number">9.2</span> Functions</h2>
|
||
<p>The basic form of function definition is:</p>
|
||
<div class="sourceCode" id="cb3"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb3-1" data-line-number="1"><span class="ot">functionName ::</span> argumentType <span class="ot">-></span> returnType</a>
|
||
<a class="sourceLine" id="cb3-2" data-line-number="2">functionName argument <span class="fu">=</span> returnValue</a></code></pre></div>
|
||
<p>For example:</p>
|
||
<div class="sourceCode" id="cb4"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb4-1" data-line-number="1"><span class="ot">repeatString ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb4-2" data-line-number="2">repeatString s <span class="fu">=</span> s <span class="fu">++</span> s</a></code></pre></div>
|
||
<p>Functions taking multiple arguments are defined in a similar manner. Note how the type of a multi-argument function looks like.</p>
|
||
<div class="sourceCode" id="cb5"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb5-1" data-line-number="1"><span class="ot">surroundString ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb5-2" data-line-number="2">surroundString around s <span class="fu">=</span> around <span class="fu">++</span> s <span class="fu">++</span> around</a></code></pre></div>
|
||
<p>Functions can be polymorphic, can take multiple arguments, and can even take functions as arguments. Here are more examples:</p>
|
||
<div class="sourceCode" id="cb6"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb6-1" data-line-number="1">id<span class="ot"> ::</span> a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb6-2" data-line-number="2">id x <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb6-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb6-4" data-line-number="4">const<span class="ot"> ::</span> a <span class="ot">-></span> b <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb6-5" data-line-number="5">const x y <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb6-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb6-7" data-line-number="7">flip<span class="ot"> ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> b <span class="ot">-></span> a <span class="ot">-></span> c</a>
|
||
<a class="sourceLine" id="cb6-8" data-line-number="8">flip f x y <span class="fu">=</span> f y x</a></code></pre></div>
|
||
<p>More sophisticated functions can be defined using <em>pattern matching</em>. We can pattern match on the <em>constructors</em> of algebraic datatypes like <code>Nothing</code>, <code>[]</code> and <code>(:)</code>.</p>
|
||
<div class="sourceCode" id="cb7"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb7-1" data-line-number="1"><span class="ot">swap ::</span> (a,b) <span class="ot">-></span> (b,a)</a>
|
||
<a class="sourceLine" id="cb7-2" data-line-number="2">swap (x,y) <span class="fu">=</span> (y,x)</a>
|
||
<a class="sourceLine" id="cb7-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb7-4" data-line-number="4">maybe<span class="ot"> ::</span> b <span class="ot">-></span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Maybe</span> a <span class="ot">-></span> b</a>
|
||
<a class="sourceLine" id="cb7-5" data-line-number="5">maybe def _ <span class="dt">Nothing</span> <span class="fu">=</span> def</a>
|
||
<a class="sourceLine" id="cb7-6" data-line-number="6">maybe _ f (<span class="dt">Just</span> x) <span class="fu">=</span> <span class="dt">Just</span> (f x)</a>
|
||
<a class="sourceLine" id="cb7-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb7-8" data-line-number="8"><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb7-9" data-line-number="9">safeHead [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb7-10" data-line-number="10">safeHead (x<span class="fu">:</span>_) <span class="fu">=</span> <span class="dt">Just</span> x</a></code></pre></div>
|
||
<p>Yet more sophistication can be achieved with <em>guards</em>. Guards let you define a function case-by-case based on tests of type <code>Bool</code>. Guards are useful in situations where pattern matching can’t be used. Of course, guards can also be combined with pattern matching:</p>
|
||
<div class="sourceCode" id="cb8"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb8-1" data-line-number="1"><span class="ot">myAbs ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb8-2" data-line-number="2">myAbs x</a>
|
||
<a class="sourceLine" id="cb8-3" data-line-number="3"> <span class="fu">|</span> x <span class="fu"><</span> <span class="dv">0</span> <span class="fu">=</span> <span class="fu">-</span>x</a>
|
||
<a class="sourceLine" id="cb8-4" data-line-number="4"> <span class="fu">|</span> otherwise <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb8-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb8-6" data-line-number="6"><span class="ot">safeDiv ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Double</span></a>
|
||
<a class="sourceLine" id="cb8-7" data-line-number="7">safeDiv x y</a>
|
||
<a class="sourceLine" id="cb8-8" data-line-number="8"> <span class="fu">|</span> y <span class="fu">==</span> <span class="dv">0</span> <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb8-9" data-line-number="9"> <span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dt">Just</span> (x <span class="fu">/</span> y)</a>
|
||
<a class="sourceLine" id="cb8-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb8-11" data-line-number="11"><span class="ot">buy ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb8-12" data-line-number="12">buy <span class="st">"Banana"</span> money</a>
|
||
<a class="sourceLine" id="cb8-13" data-line-number="13"> <span class="fu">|</span> money <span class="fu"><</span> <span class="fl">3.2</span> <span class="fu">=</span> <span class="st">"You don't have enough money for a banana"</span></a>
|
||
<a class="sourceLine" id="cb8-14" data-line-number="14"> <span class="fu">|</span> otherwise <span class="fu">=</span> <span class="st">"You bought a banana"</span></a>
|
||
<a class="sourceLine" id="cb8-15" data-line-number="15">buy product _ <span class="fu">=</span> <span class="st">"No such product: "</span> <span class="fu">++</span> product</a></code></pre></div>
|
||
<p><em>Case expressions</em> let us pattern match inside functions. They are useful in situations where the result of one function depends on the result of another and we want to match the pattern on the output of the other function:</p>
|
||
<div class="sourceCode" id="cb9"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb9-1" data-line-number="1"><span class="ot">divDefault ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></a>
|
||
<a class="sourceLine" id="cb9-2" data-line-number="2">divDefault x y def <span class="fu">=</span> <span class="kw">case</span> safeDiv x y <span class="kw">of</span></a>
|
||
<a class="sourceLine" id="cb9-3" data-line-number="3"> <span class="dt">Nothing</span> <span class="ot">-></span> def</a>
|
||
<a class="sourceLine" id="cb9-4" data-line-number="4"> <span class="dt">Just</span> w <span class="ot">-></span> w</a></code></pre></div>
|
||
<p>Let-expressions enable <em>local definitions</em>. Where-clauses work similarly to <code>let</code>s. For example:</p>
|
||
<div class="sourceCode" id="cb10"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb10-1" data-line-number="1"><span class="ot">circleArea ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></a>
|
||
<a class="sourceLine" id="cb10-2" data-line-number="2">circleArea r <span class="fu">=</span> <span class="kw">let</span> pi <span class="fu">=</span> <span class="fl">3.1415926</span></a>
|
||
<a class="sourceLine" id="cb10-3" data-line-number="3"> square x <span class="fu">=</span> x <span class="fu">*</span> x</a>
|
||
<a class="sourceLine" id="cb10-4" data-line-number="4"> <span class="kw">in</span> pi <span class="fu">*</span> square r</a>
|
||
<a class="sourceLine" id="cb10-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb10-6" data-line-number="6"><span class="ot">circleArea' ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></a>
|
||
<a class="sourceLine" id="cb10-7" data-line-number="7">circleArea' r <span class="fu">=</span> pi <span class="fu">*</span> square r</a>
|
||
<a class="sourceLine" id="cb10-8" data-line-number="8"> <span class="kw">where</span> pi <span class="fu">=</span> <span class="fl">3.1415926</span></a>
|
||
<a class="sourceLine" id="cb10-9" data-line-number="9"> square x <span class="fu">=</span> x <span class="fu">*</span> x</a></code></pre></div>
|
||
<p><em>Lambda expressions</em> are another occasionally useful syntax for defining functions. Lambda expressions represent anonymous (unnamed) functions. They can be used for defining local functions that are typically used only once.</p>
|
||
<div class="sourceCode" id="cb11"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb11-1" data-line-number="1"><span class="ot">incrementAll ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</a>
|
||
<a class="sourceLine" id="cb11-2" data-line-number="2">incrementAll xs <span class="fu">=</span> map (\x <span class="ot">-></span> x <span class="fu">+</span> <span class="dv">1</span>) xs</a></code></pre></div>
|
||
<p>Note that <code>f x = y</code> is the same thing as <code>f = \x -> y</code>.</p>
|
||
<p>Finally, binary operators have <em>sections</em>. Sections are partially applied operators. The section of an operator is obtained by writing the operator and one of its arguments in parentheses. For example, <code>(*2)</code> multiplies its argument by <code>2</code> from the right, e.g. <code>(*2) 5 ==> 5 * 2</code>. A fractional number (e.g. a <code>Double</code>) can be inverted with the section <code>(1/)</code>, e.g. <code>(1/) 2 ==> 0.5</code>.</p>
|
||
<div class="sourceCode" id="cb12"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb12-1" data-line-number="1"><span class="ot">incrementAll' ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</a>
|
||
<a class="sourceLine" id="cb12-2" data-line-number="2">incrementAll' xs <span class="fu">=</span> map (<span class="fu">+</span><span class="dv">1</span>) xs</a></code></pre></div>
|
||
<h2 id="functional-programming"><span class="header-section-number">9.3</span> Functional Programming</h2>
|
||
<p>Haskell is a functional programming language, which means that functions can be passed in as arguments and returned from functions. As a programming paradigm, functional programming aims to build programs by combining simple functions together to form larger and larger ones.</p>
|
||
<p>The most often presented example of functional programming is functional list manipulation using <em>higher-order functions</em> (functions that take functions as arguments) like <code>map</code> and <code>filter</code>. Here’s one example from part 1:</p>
|
||
<div class="sourceCode" id="cb13"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb13-1" data-line-number="1"><span class="co">-- a predicate that checks if a string is a palindrome</span></a>
|
||
<a class="sourceLine" id="cb13-2" data-line-number="2"><span class="ot">palindrome ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb13-3" data-line-number="3">palindrome str <span class="fu">=</span> str <span class="fu">==</span> reverse str</a>
|
||
<a class="sourceLine" id="cb13-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb13-5" data-line-number="5"><span class="co">-- palindromes n takes all numbers from 1 to n, converts them to</span></a>
|
||
<a class="sourceLine" id="cb13-6" data-line-number="6"><span class="co">-- strings using show, and keeps only palindromes</span></a>
|
||
<a class="sourceLine" id="cb13-7" data-line-number="7"><span class="ot">palindromes ::</span> <span class="dt">Int</span> <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb13-8" data-line-number="8">palindromes n <span class="fu">=</span> filter palindrome (map show [<span class="dv">1</span><span class="fu">..</span>n])</a></code></pre></div>
|
||
<div class="sourceCode" id="cb14"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb14-1" data-line-number="1">palindromes <span class="dv">150</span></a>
|
||
<a class="sourceLine" id="cb14-2" data-line-number="2"> <span class="fu">==></span> [<span class="st">"1"</span>,<span class="st">"2"</span>,<span class="st">"3"</span>,<span class="st">"4"</span>,<span class="st">"5"</span>,<span class="st">"6"</span>,<span class="st">"7"</span>,<span class="st">"8"</span>,<span class="st">"9"</span>,</a>
|
||
<a class="sourceLine" id="cb14-3" data-line-number="3"> <span class="st">"11"</span>,<span class="st">"22"</span>,<span class="st">"33"</span>,<span class="st">"44"</span>,<span class="st">"55"</span>,<span class="st">"66"</span>,<span class="st">"77"</span>,<span class="st">"88"</span>,<span class="st">"99"</span>,</a>
|
||
<a class="sourceLine" id="cb14-4" data-line-number="4"> <span class="st">"101"</span>,<span class="st">"111"</span>,<span class="st">"121"</span>,<span class="st">"131"</span>,<span class="st">"141"</span>]</a></code></pre></div>
|
||
<p>We also encountered other functional programming patterns in part 1, like <em>partial application</em>:</p>
|
||
<div class="sourceCode" id="cb15"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb15-1" data-line-number="1">map (take <span class="dv">3</span>) [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>],[<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span>,<span class="dv">0</span>]]</a>
|
||
<a class="sourceLine" id="cb15-2" data-line-number="2"> <span class="fu">==></span> [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>]]</a></code></pre></div>
|
||
<p>Also, <em>function composition</em>:</p>
|
||
<div class="sourceCode" id="cb16"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb16-1" data-line-number="1">(map reverse <span class="fu">.</span> filter (<span class="fu">/=</span><span class="st">"Smith"</span>)) [<span class="st">"Jones"</span>,<span class="st">"Smith"</span>,<span class="st">"White"</span>]</a>
|
||
<a class="sourceLine" id="cb16-2" data-line-number="2"> <span class="fu">==></span> [<span class="st">"senoJ"</span>,<span class="st">"etihW"</span>]</a>
|
||
<a class="sourceLine" id="cb16-3" data-line-number="3">map (negate <span class="fu">.</span> sum) [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">5</span>]]</a>
|
||
<a class="sourceLine" id="cb16-4" data-line-number="4"> <span class="fu">==></span> [<span class="fu">-</span><span class="dv">6</span>,<span class="fu">-</span><span class="dv">5</span>]</a></code></pre></div>
|
||
<p>And finally, <em>folds</em>:</p>
|
||
<div class="sourceCode" id="cb17"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb17-1" data-line-number="1">foldr (<span class="fu">*</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>] <span class="fu">==></span> <span class="dv">24</span></a>
|
||
<a class="sourceLine" id="cb17-2" data-line-number="2">foldr max <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">7</span>] <span class="fu">==></span> <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb17-3" data-line-number="3">foldr (<span class="fu">++</span>) <span class="st">""</span> [<span class="st">"abc"</span>,<span class="st">"de"</span>,<span class="st">"f"</span>] <span class="fu">==></span> <span class="st">"abcdef"</span></a></code></pre></div>
|
||
<h2 id="recursion"><span class="header-section-number">9.4</span> Recursion</h2>
|
||
<p>To implement a function that uses repetition in Haskell, you need recursion. Haskell has no loops like other programming languages. Here are some simple recursive functions in Haskell:</p>
|
||
<div class="sourceCode" id="cb18"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb18-1" data-line-number="1"><span class="ot">repeatString ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb18-2" data-line-number="2">repeatString <span class="dv">0</span> s <span class="fu">=</span> <span class="st">""</span></a>
|
||
<a class="sourceLine" id="cb18-3" data-line-number="3">repeatString n s <span class="fu">=</span> s <span class="fu">++</span> repeatString (n<span class="fu">-</span><span class="dv">1</span>) s</a>
|
||
<a class="sourceLine" id="cb18-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb18-5" data-line-number="5"><span class="ot">times ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb18-6" data-line-number="6">times <span class="dv">0</span> n <span class="fu">=</span> n</a>
|
||
<a class="sourceLine" id="cb18-7" data-line-number="7">times <span class="dv">1</span> n <span class="fu">=</span> n</a>
|
||
<a class="sourceLine" id="cb18-8" data-line-number="8">times m n <span class="fu">=</span> n <span class="fu">*</span> times (m <span class="fu">-</span> <span class="dv">1</span>) n</a>
|
||
<a class="sourceLine" id="cb18-9" data-line-number="9"></a>
|
||
<a class="sourceLine" id="cb18-10" data-line-number="10"><span class="ot">safeLast ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb18-11" data-line-number="11">safeLast [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb18-12" data-line-number="12">safeLast [x] <span class="fu">=</span> <span class="dt">Just</span> x</a>
|
||
<a class="sourceLine" id="cb18-13" data-line-number="13">safeLast (x<span class="fu">:</span>xs) <span class="fu">=</span> safeLast xs</a></code></pre></div>
|
||
<p>To consume or produce a list you often need recursion. Here are the implementations of <code>map</code> and <code>filter</code> as examples of recursive list processing:</p>
|
||
<div class="sourceCode" id="cb19"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb19-1" data-line-number="1">map<span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</a>
|
||
<a class="sourceLine" id="cb19-2" data-line-number="2">map _ [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb19-3" data-line-number="3">map f (x<span class="fu">:</span>xs) <span class="fu">=</span> f x <span class="fu">:</span> map f xs</a>
|
||
<a class="sourceLine" id="cb19-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb19-5" data-line-number="5">filter<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> [a]</a>
|
||
<a class="sourceLine" id="cb19-6" data-line-number="6">filter _ [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb19-7" data-line-number="7">filter pred (x<span class="fu">:</span>xs)</a>
|
||
<a class="sourceLine" id="cb19-8" data-line-number="8"> <span class="fu">|</span> pred x <span class="fu">=</span> x <span class="fu">:</span> filter pred xs</a>
|
||
<a class="sourceLine" id="cb19-9" data-line-number="9"> <span class="fu">|</span> otherwise <span class="fu">=</span> filter pred xs</a></code></pre></div>
|
||
<p>Sometimes, a recursive helper function is needed in case you need to keep track of multiple pieces of data.</p>
|
||
<div class="sourceCode" id="cb20"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb20-1" data-line-number="1"><span class="ot">sumNumbers ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb20-2" data-line-number="2">sumNumbers xs <span class="fu">=</span> go <span class="dv">0</span> xs</a>
|
||
<a class="sourceLine" id="cb20-3" data-line-number="3"> <span class="kw">where</span> go sum [] <span class="fu">=</span> sum</a>
|
||
<a class="sourceLine" id="cb20-4" data-line-number="4"> go sum (x<span class="fu">:</span>xs) <span class="fu">=</span> go (sum<span class="fu">+</span>x) xs</a></code></pre></div>
|
||
<p>Here’s a final example utilizing guards, pattern matching, a helper function and recursion:</p>
|
||
<div class="sourceCode" id="cb21"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb21-1" data-line-number="1"><span class="co">-- split a string into pieces at the given character</span></a>
|
||
<a class="sourceLine" id="cb21-2" data-line-number="2"><span class="ot">mySplit ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb21-3" data-line-number="3">mySplit c xs <span class="fu">=</span> helper [] xs</a>
|
||
<a class="sourceLine" id="cb21-4" data-line-number="4"> <span class="kw">where</span> helper piece [] <span class="fu">=</span> [piece]</a>
|
||
<a class="sourceLine" id="cb21-5" data-line-number="5"> helper piece (y<span class="fu">:</span>ys)</a>
|
||
<a class="sourceLine" id="cb21-6" data-line-number="6"> <span class="fu">|</span> c <span class="fu">==</span> y <span class="fu">=</span> piece <span class="fu">:</span> helper [] ys</a>
|
||
<a class="sourceLine" id="cb21-7" data-line-number="7"> <span class="fu">|</span> otherwise <span class="fu">=</span> helper (piece<span class="fu">++</span>[y]) ys</a></code></pre></div>
|
||
<div class="sourceCode" id="cb22"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb22-1" data-line-number="1">mySplit <span class="ch">'-'</span> <span class="st">"a-bcd-ef"</span> <span class="fu">==></span> [<span class="st">"a"</span>,<span class="st">"bcd"</span>,<span class="st">"ef"</span>]</a></code></pre></div>
|
||
<h2 id="type-classes"><span class="header-section-number">9.5</span> Type Classes</h2>
|
||
<p>The following functions are <em>parametrically polymorphic</em>:</p>
|
||
<div class="sourceCode" id="cb23"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb23-1" data-line-number="1">id<span class="ot"> ::</span> a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb23-2" data-line-number="2">id x <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb23-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb23-4" data-line-number="4">head<span class="ot"> ::</span> [a] <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb23-5" data-line-number="5">head (x<span class="fu">:</span>_) <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb23-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb23-7" data-line-number="7">fst<span class="ot"> ::</span> (a,b) <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb23-8" data-line-number="8">fst (x,y) <span class="fu">=</span> x</a></code></pre></div>
|
||
<p>Parametrically polymorphic functions always work the same way, no matter what types we’re working with. This means that we can’t define a special implementation of <code>id</code> just for the <code>Int</code> type, or <code>fst</code> for the type <code>(Bool, String)</code>.</p>
|
||
<p>By contrast, <em>ad hoc polymorphism</em> allows different types to have different implementations of the same function. Ad hoc polymorphism in Haskell can be achieved by defining a <em>type class</em> and then declaring <em>instances</em> of that type class for various types. Ad hoc polymorphism is a handy way for expressing a common set of operations, even when the implementation of the operations depends on the type they’re acting on.</p>
|
||
<p>Functions that use ad hoc polymorphism have a <em>class constraint</em> in their types. Here are some examples:</p>
|
||
<div class="sourceCode" id="cb24"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb24-1" data-line-number="1">negate<span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb24-2" data-line-number="2"><span class="ot">(==) ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb24-3" data-line-number="3">sort<span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> [a] <span class="ot">-></span> [a]</a></code></pre></div>
|
||
<p>A type like <code>Num a => a -> a</code> means: for any type <code>X</code> that’s a member of the <code>Num</code> class, this function has type <code>X -> X</code>. In other words, we can invoke <code>negate</code> on any number type, but not on other types:</p>
|
||
<div class="sourceCode" id="cb25"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb25-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> negate <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb25-2" data-line-number="2"><span class="fu">-</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb25-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> negate <span class="fl">1.0</span></a>
|
||
<a class="sourceLine" id="cb25-4" data-line-number="4"><span class="fu">-</span><span class="fl">1.0</span></a>
|
||
<a class="sourceLine" id="cb25-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> negate <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb25-6" data-line-number="6"><span class="fu"><</span>interactive<span class="fu">>:</span><span class="dv">3</span><span class="fu">:</span><span class="dv">1</span><span class="fu">:</span> error<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb25-7" data-line-number="7"> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Num</span> <span class="dt">Bool</span>) arising from a use <span class="kw">of</span> ‘negate’</a></code></pre></div>
|
||
<p>Here’s a summary of some useful type classes from the standard library.</p>
|
||
<ul>
|
||
<li>Comparison
|
||
<ul>
|
||
<li><code>Eq</code> is for equality comparison. It contains the <code>==</code> operator</li>
|
||
<li><code>Ord</code> is for order comparison. It contains the ordered comparison operators like <code><</code> and <code>=></code>, and functions like <code>max</code> and <code>min</code>.</li>
|
||
</ul></li>
|
||
<li>Numbers
|
||
<ul>
|
||
<li><code>Num</code> is for all number types. It contains <code>+</code>, <code>-</code>, <code>*</code> and <code>negate</code>.</li>
|
||
<li><code>Integral</code> is for whole number types. Most notably, it contains integer division <code>div</code>.</li>
|
||
<li><code>Fractional</code> is for number types that support division, <code>/</code></li>
|
||
</ul></li>
|
||
<li>Converting values to strings
|
||
<ul>
|
||
<li><code>Show</code> contains the function <code>show :: Show a => a -> String</code> that converts values to strings</li>
|
||
<li><code>Read</code> contains the function <code>read :: Read a => String -> a</code> that is the inverse of <code>show</code></li>
|
||
</ul></li>
|
||
</ul>
|
||
<p>Sometimes, multiple class constraints are needed. For instance here:</p>
|
||
<div class="sourceCode" id="cb26"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb26-1" data-line-number="1"><span class="ot">sumTwoSmallest ::</span> (<span class="dt">Num</span> a, <span class="dt">Ord</span> a) <span class="ot">=></span> [a] <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb26-2" data-line-number="2">sumTwoSmallest xs <span class="fu">=</span> <span class="kw">let</span> (a<span class="fu">:</span>b<span class="fu">:</span>_) <span class="fu">=</span> sort xs</a>
|
||
<a class="sourceLine" id="cb26-3" data-line-number="3"> <span class="kw">in</span> a<span class="fu">+</span>b</a></code></pre></div>
|
||
<p>Now that we’ve seen some classes and types, let’s look at the syntax of declaring classes and instances. Here are two class definitions:</p>
|
||
<div class="sourceCode" id="cb27"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb27-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Sized</span> a <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb27-2" data-line-number="2"><span class="ot"> empty ::</span> a <span class="co">-- a thing with size 0</span></a>
|
||
<a class="sourceLine" id="cb27-3" data-line-number="3"><span class="ot"> size ::</span> a <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb27-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb27-5" data-line-number="5"><span class="kw">class</span> <span class="dt">Eq</span> a <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb27-6" data-line-number="6"><span class="ot"> (==) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></a></code></pre></div>
|
||
<p>Consider the following data structures:</p>
|
||
<div class="sourceCode" id="cb28"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb28-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Numbers</span> <span class="fu">=</span> <span class="dt">None</span> <span class="fu">|</span> <span class="dt">One</span> <span class="dt">Int</span> <span class="fu">|</span> <span class="dt">Two</span> <span class="dt">Int</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb28-2" data-line-number="2"><span class="kw">data</span> <span class="dt">IntList</span> <span class="fu">=</span> <span class="dt">Nil</span> <span class="fu">|</span> <span class="dt">ListNode</span> <span class="dt">Int</span> <span class="dt">IntList</span></a>
|
||
<a class="sourceLine" id="cb28-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Tree</span> a <span class="fu">=</span> <span class="dt">Leaf</span> <span class="fu">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</a></code></pre></div>
|
||
<p>All of these have sizes that we can count, but we need to perform the operation differently:</p>
|
||
<div class="sourceCode" id="cb29"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb29-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Sized</span> <span class="dt">Numbers</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb29-2" data-line-number="2"> empty <span class="fu">=</span> <span class="dt">None</span></a>
|
||
<a class="sourceLine" id="cb29-3" data-line-number="3"> size <span class="dt">None</span> <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb29-4" data-line-number="4"> size (<span class="dt">One</span> _) <span class="fu">=</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb29-5" data-line-number="5"> size (<span class="dt">Two</span> _ _) <span class="fu">=</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb29-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb29-7" data-line-number="7"><span class="kw">instance</span> <span class="dt">Sized</span> <span class="dt">IntList</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb29-8" data-line-number="8"> empty <span class="fu">=</span> <span class="dt">Nil</span></a>
|
||
<a class="sourceLine" id="cb29-9" data-line-number="9"> size <span class="dt">Nil</span> <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb29-10" data-line-number="10"> size (<span class="dt">ListNode</span> _ list) <span class="fu">=</span> <span class="dv">1</span> <span class="fu">+</span> size list</a>
|
||
<a class="sourceLine" id="cb29-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb29-12" data-line-number="12"><span class="kw">instance</span> <span class="dt">Sized</span> (<span class="dt">Tree</span> a) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb29-13" data-line-number="13"> empty <span class="fu">=</span> <span class="dt">Leaf</span></a>
|
||
<a class="sourceLine" id="cb29-14" data-line-number="14"> size <span class="dt">Leaf</span> <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb29-15" data-line-number="15"> size (<span class="dt">Node</span> _ left right) <span class="fu">=</span> <span class="dv">1</span> <span class="fu">+</span> size left <span class="fu">+</span> size right</a></code></pre></div>
|
||
<p>We can also easily declare <code>Eq</code> instances for <code>Numbers</code> and <code>IntList</code>:</p>
|
||
<div class="sourceCode" id="cb30"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb30-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">Numbers</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb30-2" data-line-number="2"> <span class="dt">None</span> <span class="fu">==</span> <span class="dt">None</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb30-3" data-line-number="3"> (<span class="dt">One</span> x) <span class="fu">==</span> (<span class="dt">One</span> y) <span class="fu">=</span> x<span class="fu">==</span>y</a>
|
||
<a class="sourceLine" id="cb30-4" data-line-number="4"> (<span class="dt">Two</span> x y) <span class="fu">==</span> (<span class="dt">Two</span> z w) <span class="fu">=</span> x<span class="fu">==</span>z <span class="fu">&&</span> y<span class="fu">==</span>w</a>
|
||
<a class="sourceLine" id="cb30-5" data-line-number="5"> _ <span class="fu">==</span> _ <span class="fu">=</span> <span class="dt">False</span> <span class="co">-- to handle cases like None == One 1</span></a>
|
||
<a class="sourceLine" id="cb30-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb30-7" data-line-number="7"><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">IntList</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb30-8" data-line-number="8"> <span class="dt">Nil</span> <span class="fu">==</span> <span class="dt">Nil</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb30-9" data-line-number="9"> (<span class="dt">ListNode</span> x xs) <span class="fu">==</span> (<span class="dt">ListNode</span> y ys) <span class="fu">=</span> x <span class="fu">==</span> y <span class="fu">&&</span> xs <span class="fu">==</span> ys</a>
|
||
<a class="sourceLine" id="cb30-10" data-line-number="10"> _ <span class="fu">==</span> _ <span class="fu">=</span> <span class="dt">False</span></a></code></pre></div>
|
||
<p>However, since the <code>Tree</code> datatype is parameterized over the element type <code>a</code>, we need an <code>Eq a</code> instance in order to have an <code>Eq (Tree a)</code> instance. This is achieved by adding a class constraint to the instance declaration. This is called an <em>instance hierarchy</em>.</p>
|
||
<div class="sourceCode" id="cb31"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb31-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Eq</span> a <span class="ot">=></span> <span class="dt">Eq</span> (<span class="dt">Tree</span> a) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb31-2" data-line-number="2"> <span class="dt">Leaf</span> <span class="fu">==</span> <span class="dt">Leaf</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb31-3" data-line-number="3"> (<span class="dt">Node</span> x l r) <span class="fu">==</span> (<span class="dt">Node</span> x' l' r') <span class="fu">=</span> x <span class="fu">==</span> x' <span class="fu">&&</span> l <span class="fu">==</span> l' <span class="fu">&&</span> r <span class="fu">==</span> r'</a>
|
||
<a class="sourceLine" id="cb31-4" data-line-number="4"> _ <span class="fu">==</span> _ <span class="fu">=</span> <span class="dt">False</span></a></code></pre></div>
|
||
<h3 id="deriving"><span class="header-section-number">9.5.1</span> Deriving</h3>
|
||
<p>Some standard type classes, most notably <code>Show</code>, <code>Read</code>, <code>Eq</code> and <code>Ord</code> can be <em>derived</em>, that is, you can ask the compiler to generate automatic instances for you. For example we could have derived all of these classes for our earlier <code>Numbers</code> example.</p>
|
||
<div class="sourceCode" id="cb32"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb32-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Numbers</span> <span class="fu">=</span> <span class="dt">None</span> <span class="fu">|</span> <span class="dt">One</span> <span class="dt">Int</span> <span class="fu">|</span> <span class="dt">Two</span> <span class="dt">Int</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb32-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Read</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb33"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb33-1" data-line-number="1"><span class="dt">None</span> <span class="fu">==</span> <span class="dt">One</span> <span class="dv">1</span> <span class="fu">==></span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb33-2" data-line-number="2"><span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="fu">==</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="fu">==></span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb33-3" data-line-number="3"><span class="dt">None</span> <span class="fu"><</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="fu">==></span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb33-4" data-line-number="4"><span class="dt">Two</span> <span class="dv">1</span> <span class="dv">3</span> <span class="fu"><</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="fu">==></span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb33-5" data-line-number="5">show (<span class="dt">Two</span> <span class="dv">1</span> <span class="dv">3</span>) <span class="fu">==></span> <span class="st">"Two 1 3"</span></a></code></pre></div>
|
||
<h2 id="quiz"><span class="header-section-number">9.6</span> Quiz</h2>
|
||
<p>What is the type of <code>('c',not)</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>[Char]</code>
|
||
</li>
|
||
<li>
|
||
<code>[Bool]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(Char,Bool -> Bool)</code>
|
||
</li>
|
||
<li>
|
||
<code>(Char,Bool)</code>
|
||
</li>
|
||
<li>
|
||
It is a type error.
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>['c',not]</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>[Char]</code>
|
||
</li>
|
||
<li>
|
||
<code>[Bool]</code>
|
||
</li>
|
||
<li>
|
||
<code>(Char,Bool -> Bool)</code>
|
||
</li>
|
||
<li>
|
||
<code>(Char,Bool)</code>
|
||
</li>
|
||
<li class="correct">
|
||
It is a type error.
|
||
</li>
|
||
</ol>
|
||
<p>Which of these is a value of the following type?</p>
|
||
<div class="sourceCode" id="cb34"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb34-1" data-line-number="1"><span class="kw">data</span> <span class="dt">T</span> <span class="fu">=</span> <span class="dt">X</span> <span class="dt">Int</span> <span class="fu">|</span> <span class="dt">Y</span> <span class="dt">String</span> <span class="dt">String</span> <span class="fu">|</span> <span class="dt">Z</span> <span class="dt">T</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>X "foo"</code>
|
||
</li>
|
||
<li>
|
||
<code>Y "foo"</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Z (X 1)</code>
|
||
</li>
|
||
<li>
|
||
<code>X (Z 1)</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of this function?</p>
|
||
<div class="sourceCode" id="cb35"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb35-1" data-line-number="1">f (_<span class="fu">:</span><span class="dt">Just</span> x<span class="fu">:</span>_) <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb35-2" data-line-number="2">f _ <span class="fu">=</span> <span class="dt">False</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Maybe a -> a</code>
|
||
</li>
|
||
<li>
|
||
<code>[Maybe a] -> a</code>
|
||
</li>
|
||
<li>
|
||
<code>[Maybe a] -> Bool</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>[Maybe Bool] -> Bool</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of this function?</p>
|
||
<div class="sourceCode" id="cb36"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb36-1" data-line-number="1">f x y <span class="fu">=</span> x<span class="fu">-</span>y <span class="fu">==</span> <span class="dv">0</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
(Num a, Eq a) => a -> a -> Bool
|
||
</li>
|
||
<li>
|
||
<code>Num a => a -> a -> Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>Eq a => a -> a -> Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> a -> Bool</code>
|
||
</li>
|
||
</ol>
|
||
<h2 id="working-on-the-exercises"><span class="header-section-number">9.7</span> Working on the Exercises</h2>
|
||
<p>Here’s a short recap of how to work on the exercises. The system is the same as for part 1 of the course.</p>
|
||
<ol type="1">
|
||
<li>Clone the GitHub repository <a href="https://github.com/moocfi/haskell-mooc" class="uri">https://github.com/moocfi/haskell-mooc</a></li>
|
||
<li>Go to the <code>exercises/</code> directory</li>
|
||
<li>Run <code>stack build</code> to download dependencies</li>
|
||
<li>Edit the file <code>Set9a.hs</code></li>
|
||
<li>Check your answers by running <code>stack runhaskell Set9aTest.hs</code></li>
|
||
<li>Return your answers on the <a href="https://haskell.mooc.fi/submit.php">Submit page</a></li>
|
||
<li>Repeat as necessary. You can work on the exercise sets in any order, and you can return the sets as many times as you want!</li>
|
||
<li>You can see total score on the <a href="https://haskell.mooc.fi/status.php">My status page</a></li>
|
||
</ol>
|
||
<h2 id="exercises"><span class="header-section-number">9.8</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set9a.hs">Set9a</a> - small exercises that recap part 1 of the course</li>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set9b.hs">Set9b</a> - let’s solve the N Queens puzzle!</li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
<h1 id="lecture-10-reductionism"><span class="header-section-number">10</span> Lecture 10: Reductionism</h1>
|
||
<ul>
|
||
<li>Purity</li>
|
||
<li>Laziness</li>
|
||
<li>Haskell evaluation</li>
|
||
</ul>
|
||
<h2 id="laziness-purity"><span class="header-section-number">10.1</span> Laziness & Purity</h2>
|
||
<p>Purity and laziness were mentioned as key features of Haskell in the beginning of part 1. Let’s take a closer look at them.</p>
|
||
<p>Haskell is a <em>pure</em> functional language. This means that the value <code>f x y</code> is always the same for given <code>x</code> and <code>y</code>. In other words, the values of <code>x</code> and <code>y</code> uniquely determine the value of <code>f x y</code>. This property is also called <em>referential transparency</em>.</p>
|
||
<p>Purity also means that there are no side effects: you can’t have the evaluation of <code>f x y</code> read a line from the user - the line would be different on different invocations of <code>f</code> and would affect the return value, breaking referential transparency! Obviously you need side effects to actually get something done. We’ll get back to how Haskell handles side effects later.</p>
|
||
<p>Haskell is a <em>lazy</em> language. This means that a value is not evaluated if it is not needed. An example illustrates this best. Consider these two functions:</p>
|
||
<div class="sourceCode" id="cb37"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb37-1" data-line-number="1">f x <span class="fu">=</span> f x <span class="co">-- infinite recursion</span></a>
|
||
<a class="sourceLine" id="cb37-2" data-line-number="2">g x y <span class="fu">=</span> x</a></code></pre></div>
|
||
<p>Evaluating <code>f 1</code> does not halt due to the infinite recursion. However, this works:</p>
|
||
<div class="sourceCode" id="cb38"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb38-1" data-line-number="1">g <span class="dv">2</span> (f <span class="dv">1</span>) <span class="fu">==></span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>Laziness is not a problem because Haskell is pure. Only the result of the function matters, not the side effects. So if the result of a function is not used, we can simply not evaluate it without changing the meaning (semantics) of a program. Well okay, sometimes we get a terminating program instead of one that goes on for ever, but adding laziness never makes a functioning Haskell program break.</p>
|
||
<p>If you’re interested in the theory behind this, check out the <a href="https://en.wikipedia.org/wiki/Church%E2%80%93Rosser_theorem">Church-Rosser theorem</a> or the Haskell Wiki article <a href="https://wiki.haskell.org/Lazy_vs._non-strict">Lazy vs. non-strict</a>.</p>
|
||
<h2 id="equational-reasoning"><span class="header-section-number">10.2</span> Equational Reasoning</h2>
|
||
<p>Referential transparency, the feature that an expression always returns the same value for the same inputs, is a very powerful property that we can leverage to <em>reason about programs</em>.</p>
|
||
<p>In a C-style language, we might write a procedure that may not always return the same value for the same arguments:</p>
|
||
<pre><code>int c = 0;
|
||
int funny(int x) {
|
||
return x + c++;
|
||
}</code></pre>
|
||
<p>The expression <code>c++</code> increments the value of <code>c</code> and returns the old value of <code>c</code>. The next time it is evaluated, the value of <code>c</code> has increased by one. This means that depending on the current value of <code>c</code>, <code>funny(0)</code> might return <code>0</code>, <code>1</code>, <code>2</code>, or any other integer value. (It might even return negative values if <code>c</code> overflows!)</p>
|
||
<p>In some situations this kind of behaviour with side-effects may be useful, but there are also times when it is more important to be able to reason about the code easily. The advantage of pure functions is that they can be analyzed using basic mathematical techniques. Sometimes applying math to our functions can even reveal simplifications or optimisations we otherwise wouldn’t have thought about.</p>
|
||
<p>Consider the following expression:</p>
|
||
<div class="sourceCode" id="cb40"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb40-1" data-line-number="1">map (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> reverse <span class="fu">.</span> map (<span class="fu">-</span><span class="dv">1</span>)</a></code></pre></div>
|
||
<p>This expression can be simplified to just <code>reverse</code>. We begin by establishing some helpful facts (or <em>lemmas</em>). First, suppose that we know</p>
|
||
<ol type="1">
|
||
<li><code>map id === id</code></li>
|
||
<li><code>map f . map g === map (f.g)</code></li>
|
||
<li><code>reverse . map f === map f . reverse</code></li>
|
||
</ol>
|
||
<p>The fourth fact that we’re going to need is the following:</p>
|
||
<ol start="4" type="1">
|
||
<li><code>(+1) . (-1) === id</code></li>
|
||
</ol>
|
||
<p>We can prove fact 4 by reasoning about how <code>(+1) . (-1)</code> behaves for an arbitrary input <code>x</code>:</p>
|
||
<div class="sourceCode" id="cb41"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb41-1" data-line-number="1">((<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> (<span class="fu">-</span><span class="dv">1</span>)) x <span class="fu">===</span> ((<span class="fu">+</span><span class="dv">1</span>) ((<span class="fu">-</span><span class="dv">1</span>) x))</a>
|
||
<a class="sourceLine" id="cb41-2" data-line-number="2"> <span class="fu">===</span> ((<span class="fu">+</span><span class="dv">1</span>) (x <span class="fu">-</span> <span class="dv">1</span>))</a>
|
||
<a class="sourceLine" id="cb41-3" data-line-number="3"> <span class="fu">===</span> (x <span class="fu">-</span> <span class="dv">1</span>) <span class="fu">+</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb41-4" data-line-number="4"> <span class="fu">===</span> x</a>
|
||
<a class="sourceLine" id="cb41-5" data-line-number="5"> <span class="fu">===</span> id x</a></code></pre></div>
|
||
<p>Because we didn’t assume anything about <code>x</code>, we may conclude that the above chain of equations holds for <em>all</em> <code>x</code>s. Thus,</p>
|
||
<div class="sourceCode" id="cb42"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb42-1" data-line-number="1">(<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> (<span class="fu">-</span><span class="dv">1</span>) <span class="fu">===</span> id</a></code></pre></div>
|
||
<p>For those who are familiar with the technique of <em>proof by induction</em>, it is a fun exercise to prove the first three facts also. This course doesn’t discuss induction proofs, though, so don’t sweat if you don’t know induction.</p>
|
||
<p>Now, from facts 1-4 it follows that</p>
|
||
<div class="sourceCode" id="cb43"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb43-1" data-line-number="1"> map (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> reverse <span class="fu">.</span> map (<span class="fu">-</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb43-2" data-line-number="2"><span class="fu">===</span> map (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> (reverse <span class="fu">.</span> map (<span class="fu">-</span><span class="dv">1</span>)) <span class="co">-- By associativity of (.)</span></a>
|
||
<a class="sourceLine" id="cb43-3" data-line-number="3"><span class="fu">===</span> map (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> (map (<span class="fu">-</span><span class="dv">1</span>) <span class="fu">.</span> reverse) <span class="co">-- By fact 3</span></a>
|
||
<a class="sourceLine" id="cb43-4" data-line-number="4"><span class="fu">===</span> (map (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> map (<span class="fu">-</span><span class="dv">1</span>)) <span class="fu">.</span> reverse <span class="co">-- By associativity of (.)</span></a>
|
||
<a class="sourceLine" id="cb43-5" data-line-number="5"><span class="fu">===</span> map ((<span class="fu">+</span><span class="dv">1</span>) <span class="fu">.</span> (<span class="fu">-</span><span class="dv">1</span>)) <span class="fu">.</span> reverse <span class="co">-- By fact 2</span></a>
|
||
<a class="sourceLine" id="cb43-6" data-line-number="6"><span class="fu">===</span> map id <span class="fu">.</span> reverse <span class="co">-- By fact 4</span></a>
|
||
<a class="sourceLine" id="cb43-7" data-line-number="7"><span class="fu">===</span> id <span class="fu">.</span> reverse <span class="co">-- By fact 1</span></a>
|
||
<a class="sourceLine" id="cb43-8" data-line-number="8"><span class="fu">===</span> reverse <span class="co">-- By the definition of id</span></a></code></pre></div>
|
||
<p>This course won’t go into detail about proving things about programs, but it’s good to know that pure functional programming is very compatible with analysis like this.</p>
|
||
<h2 id="infinite-lists"><span class="header-section-number">10.3</span> Infinite Lists</h2>
|
||
<p>The benefits of laziness are best demonstrated with some examples involving <em>infinite lists</em>. Let’s start with <code>repeat 1</code>, which generates an infinite list of <code>1</code>s. If we try to tell GHCi to print the value <code>repeat 1</code>, it will just keep printing <code>1</code>s for ever until we interrupt it using Control-C:</p>
|
||
<div class="sourceCode" id="cb44"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb44-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> repeat <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb44-2" data-line-number="2">[<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb44-3" data-line-number="3"><span class="fu">^</span><span class="dt">C</span></a></code></pre></div>
|
||
<p>However, due to laziness, we can work with infinite lists and write computations that end. We just need to use a finite number of elements from the infinite list. Here are some examples:</p>
|
||
<div class="sourceCode" id="cb45"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb45-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">10</span> <span class="fu">$</span> repeat <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb45-2" data-line-number="2">[<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb45-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">20</span> <span class="fu">$</span> repeat <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb45-4" data-line-number="4">[<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb45-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> repeat <span class="dv">1</span> <span class="fu">!!</span> <span class="dv">13337</span></a>
|
||
<a class="sourceLine" id="cb45-6" data-line-number="6"><span class="dv">1</span></a></code></pre></div>
|
||
<p>An infinite list that just repeats one element can sometimes be necessary, but it’s kind of pointless. Let’s look at some more useful infinite lists next. You can use the <code>[n..]</code> syntax to generate an infinite list of numbers, starting from <code>n</code>:</p>
|
||
<div class="sourceCode" id="cb46"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb46-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">20</span> [<span class="dv">0</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb46-2" data-line-number="2">[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>,<span class="dv">9</span>,<span class="dv">10</span>,<span class="dv">11</span>,<span class="dv">12</span>,<span class="dv">13</span>,<span class="dv">14</span>,<span class="dv">15</span>,<span class="dv">16</span>,<span class="dv">17</span>,<span class="dv">18</span>,<span class="dv">19</span>]</a>
|
||
<a class="sourceLine" id="cb46-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">10</span> <span class="fu">.</span> map (<span class="dv">2</span><span class="fu">^</span>) <span class="fu">$</span> [<span class="dv">0</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb46-4" data-line-number="4">[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">8</span>,<span class="dv">16</span>,<span class="dv">32</span>,<span class="dv">64</span>,<span class="dv">128</span>,<span class="dv">256</span>,<span class="dv">512</span>]</a></code></pre></div>
|
||
<p>The function <code>cycle</code> repeats elements from the given list over and over again. It can be useful when dealing with rotations or cycles.</p>
|
||
<div class="sourceCode" id="cb47"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb47-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">21</span> <span class="fu">$</span> cycle <span class="st">"asdf"</span></a>
|
||
<a class="sourceLine" id="cb47-2" data-line-number="2"><span class="st">"asdfasdfasdfasdfasdfa"</span></a>
|
||
<a class="sourceLine" id="cb47-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">4</span> <span class="fu">.</span> map (take <span class="dv">4</span>) <span class="fu">.</span> tails <span class="fu">$</span> cycle <span class="st">"asdf"</span></a>
|
||
<a class="sourceLine" id="cb47-4" data-line-number="4">[<span class="st">"asdf"</span>,<span class="st">"sdfa"</span>,<span class="st">"dfas"</span>,<span class="st">"fasd"</span>]</a></code></pre></div>
|
||
<h3 id="example-transaction-numbers"><span class="header-section-number">10.3.1</span> Example: Transaction Numbers</h3>
|
||
<p>As a more concrete example of how <code>cycle</code> is useful, let’s look at computing the check digit of Finnish bank transfer transaction numbers (<a href="https://fi.wikipedia.org/wiki/Tilisiirto#Viitenumero">viitenumero</a>). A transaction number consists of any number of digits, followed by a single check digit. The check digit is checked by multiplying the digits (from right to left) with the numbers 7, 3, 1, 7, 3, 1 and so on, and summing the results. If the result of the sum <em>plus the check digit</em> is divisible by 10, the number is valid.</p>
|
||
<p>Here’s a concrete example. <code>116127</code> is a valid transaction number. The computation goes like this:</p>
|
||
<pre><code>digits: 1 1 6 1 2
|
||
* * * * *
|
||
multipliers: 3 7 1 3 7
|
||
3+ 7+ 6+ 3+14 = 33
|
||
check digit is 7, 33+7=40 is divisible by 10, valid</code></pre>
|
||
<p>Here’s the Haskell code for a transaction number checker. Note how we use use the infinite list <code>cycle [7,3,1]</code> for the multipliers.</p>
|
||
<div class="sourceCode" id="cb49"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb49-1" data-line-number="1"><span class="ot">viitenumeroCheck ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb49-2" data-line-number="2">viitenumeroCheck allDigits <span class="fu">=</span> mod (checksum<span class="fu">+</span>checkDigit) <span class="dv">10</span> <span class="fu">==</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb49-3" data-line-number="3"> <span class="kw">where</span> (checkDigit<span class="fu">:</span>digits) <span class="fu">=</span> reverse allDigits</a>
|
||
<a class="sourceLine" id="cb49-4" data-line-number="4"> multipliers <span class="fu">=</span> cycle [<span class="dv">7</span>,<span class="dv">3</span>,<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb49-5" data-line-number="5"> checksum <span class="fu">=</span> sum <span class="fu">$</span> zipWith (<span class="fu">*</span>) multipliers digits</a></code></pre></div>
|
||
<div class="sourceCode" id="cb50"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb50-1" data-line-number="1">viitenumeroCheck [<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">6</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">7</span>] <span class="fu">==></span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb50-2" data-line-number="2">viitenumeroCheck [<span class="dv">1</span>,<span class="dv">1</span>,<span class="dv">6</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">8</span>] <span class="fu">==></span> <span class="dt">False</span></a></code></pre></div>
|
||
<h3 id="example-finding-a-power"><span class="header-section-number">10.3.2</span> Example: Finding a Power</h3>
|
||
<p>Finally, here’s how you would find the first power of 3 that’s larger than 100.</p>
|
||
<div class="sourceCode" id="cb51"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb51-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> head <span class="fu">.</span> filter (<span class="fu">></span><span class="dv">100</span>) <span class="fu">$</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">0</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb51-2" data-line-number="2"><span class="dv">243</span></a></code></pre></div>
|
||
<p>Let’s go through how this works step by step. Note how map and filter are processing the list lazily, one element at a time, as needed. This is similar to how <em>generators</em> or <em>iterators</em> work in languages like Python or Java.</p>
|
||
<div class="sourceCode" id="cb52"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb52-1" data-line-number="1"> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb52-2" data-line-number="2"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) (<span class="dv">0</span><span class="fu">:</span>[<span class="dv">1</span><span class="fu">..</span>]))) <span class="co">-- evaluate first element of the lazy list</span></a>
|
||
<a class="sourceLine" id="cb52-3" data-line-number="3"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">1</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>])) <span class="co">-- map processes the element</span></a>
|
||
<a class="sourceLine" id="cb52-4" data-line-number="4"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>])) <span class="co">-- filter drops the element</span></a>
|
||
<a class="sourceLine" id="cb52-5" data-line-number="5"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) (<span class="dv">1</span><span class="fu">:</span>[<span class="dv">2</span><span class="fu">..</span>]))) <span class="co">-- evaluate second element of the lazy list</span></a>
|
||
<a class="sourceLine" id="cb52-6" data-line-number="6"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">3</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">2</span><span class="fu">..</span>])) <span class="co">-- map processes the element</span></a>
|
||
<a class="sourceLine" id="cb52-7" data-line-number="7"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">2</span><span class="fu">..</span>])) <span class="co">-- filter drops the element</span></a>
|
||
<a class="sourceLine" id="cb52-8" data-line-number="8"><span class="co">-- let's take bigger steps now</span></a>
|
||
<a class="sourceLine" id="cb52-9" data-line-number="9"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">9</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">3</span><span class="fu">..</span>])) <span class="co">-- map processes, filter will drop</span></a>
|
||
<a class="sourceLine" id="cb52-10" data-line-number="10"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">27</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">4</span><span class="fu">..</span>])) <span class="co">-- map processes, filter will drop</span></a>
|
||
<a class="sourceLine" id="cb52-11" data-line-number="11"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">81</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">5</span><span class="fu">..</span>])) <span class="co">-- map processes, filter will drop</span></a>
|
||
<a class="sourceLine" id="cb52-12" data-line-number="12"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">243</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">6</span><span class="fu">..</span>])) <span class="co">-- map processes</span></a>
|
||
<a class="sourceLine" id="cb52-13" data-line-number="13"><span class="fu">==></span> head (<span class="dv">243</span> <span class="fu">:</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">6</span><span class="fu">..</span>])) <span class="co">-- filter lets the value through</span></a>
|
||
<a class="sourceLine" id="cb52-14" data-line-number="14"><span class="fu">==></span> <span class="dv">243</span> <span class="co">-- head returns the result</span></a></code></pre></div>
|
||
<h2 id="how-does-haskell-work"><span class="header-section-number">10.4</span> How does Haskell Work?</h2>
|
||
<p>Laziness will probably feel a bit magical to you right now. You might wonder how it can be implemented. Haskell evaluation is remarkably simple, it’s just different than what you might be used to. Let’s dig in.</p>
|
||
<p>In most other programming languages (like Java, C or Python), evaluation proceeds inside-out. Arguments to functions are evaluated before the function.</p>
|
||
<p>Haskell evaluation proceeds outside-in instead of inside-out. The definition of the outermost function in an expression is applied without evaluating any arguments. Here’s a concrete example with toy functions <code>f</code> and <code>g</code>:</p>
|
||
<div class="sourceCode" id="cb53"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb53-1" data-line-number="1"><span class="ot">g ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb53-2" data-line-number="2">g x y <span class="fu">=</span> y<span class="fu">+</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb53-3" data-line-number="3"><span class="ot">f ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb53-4" data-line-number="4">f a b c <span class="fu">=</span> g (a<span class="fu">*</span><span class="dv">1000</span>) c</a></code></pre></div>
|
||
<p>Inside-out (normal) evaluation:</p>
|
||
<div class="sourceCode" id="cb54"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb54-1" data-line-number="1">f <span class="dv">1</span> (<span class="dv">1234</span><span class="fu">*</span><span class="dv">1234</span>) <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb54-2" data-line-number="2"> <span class="co">-- evaluate arguments to f</span></a>
|
||
<a class="sourceLine" id="cb54-3" data-line-number="3"> <span class="fu">==></span> f <span class="dv">1</span> <span class="dv">1522756</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb54-4" data-line-number="4"> <span class="co">-- evaluate f</span></a>
|
||
<a class="sourceLine" id="cb54-5" data-line-number="5"> <span class="fu">==></span> g (<span class="dv">1</span><span class="fu">*</span><span class="dv">1000</span>) <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb54-6" data-line-number="6"> <span class="co">-- evaluate arguments to g</span></a>
|
||
<a class="sourceLine" id="cb54-7" data-line-number="7"> <span class="fu">==></span> g <span class="dv">1000</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb54-8" data-line-number="8"> <span class="co">-- evaluate g</span></a>
|
||
<a class="sourceLine" id="cb54-9" data-line-number="9"> <span class="fu">==></span> <span class="dv">2</span><span class="fu">+</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb54-10" data-line-number="10"> <span class="fu">==></span> <span class="dv">3</span></a></code></pre></div>
|
||
<p>Haskell outside-in evaluation:</p>
|
||
<div class="sourceCode" id="cb55"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb55-1" data-line-number="1">f <span class="dv">1</span> (<span class="dv">1234</span><span class="fu">*</span><span class="dv">1234</span>) <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb55-2" data-line-number="2"> <span class="co">-- evaluate f without evaluating arguments</span></a>
|
||
<a class="sourceLine" id="cb55-3" data-line-number="3"> <span class="fu">==></span> g (<span class="dv">1</span><span class="fu">*</span><span class="dv">1000</span>) <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb55-4" data-line-number="4"> <span class="co">-- evaluate g without evaluating arguments</span></a>
|
||
<a class="sourceLine" id="cb55-5" data-line-number="5"> <span class="fu">==></span> <span class="dv">2</span><span class="fu">+</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb55-6" data-line-number="6"> <span class="fu">==></span> <span class="dv">3</span></a></code></pre></div>
|
||
<p>Note how the unused calculations <code>1234*1234</code> and <code>1*1000</code> didn’t get evaluated. This is why laziness is often helpful.</p>
|
||
<h3 id="pattern-matching-drives-evaluation"><span class="header-section-number">10.4.1</span> Pattern Matching Drives Evaluation</h3>
|
||
<p>Let’s look at a more involved example, with pattern matching and more complex data (lists). Pattern matching drives Haskell evaluation in a very concrete way, as we’ll see. Here are some functions that we’ll use. They’re familiar from the Prelude, but I’ll give them simple definitions.</p>
|
||
<div class="sourceCode" id="cb56"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb56-1" data-line-number="1">not <span class="dt">True</span> <span class="fu">=</span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb56-2" data-line-number="2">not <span class="dt">False</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb56-3" data-line-number="3">map f [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb56-4" data-line-number="4">map f (x<span class="fu">:</span>xs) <span class="fu">=</span> f x <span class="fu">:</span> map f xs</a>
|
||
<a class="sourceLine" id="cb56-5" data-line-number="5">length [] <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb56-6" data-line-number="6">length (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dv">1</span><span class="fu">+</span>length xs</a></code></pre></div>
|
||
<p>Here’s the inside-out evaluation of an expression:</p>
|
||
<div class="sourceCode" id="cb57"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb57-1" data-line-number="1">length (map not (<span class="dt">True</span><span class="fu">:</span><span class="dt">False</span><span class="fu">:</span>[]))</a>
|
||
<a class="sourceLine" id="cb57-2" data-line-number="2"> <span class="fu">==></span> length (not <span class="dt">True</span> <span class="fu">:</span> not <span class="dt">False</span> <span class="fu">:</span> []) <span class="co">-- evaluate call to map</span></a>
|
||
<a class="sourceLine" id="cb57-3" data-line-number="3"> <span class="fu">==></span> length (<span class="dt">False</span><span class="fu">:</span><span class="dt">True</span><span class="fu">:</span>[]) <span class="co">-- evaluate calls to not</span></a>
|
||
<a class="sourceLine" id="cb57-4" data-line-number="4"> <span class="fu">==></span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>Here’s how the evaluation proceeds in Haskell. Note how it’s not strictly outside-in, since we sometimes need to evaluate inside arguments to be able to know which pattern is matched.</p>
|
||
<div class="sourceCode" id="cb58"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb58-1" data-line-number="1">length (map not (<span class="dt">True</span><span class="fu">:</span><span class="dt">False</span><span class="fu">:</span>[]))</a>
|
||
<a class="sourceLine" id="cb58-2" data-line-number="2"> <span class="co">-- We can't evaluate length since we don't know which equation of length applies,</span></a>
|
||
<a class="sourceLine" id="cb58-3" data-line-number="3"> <span class="co">-- so we look at length's argument. We can apply the second equation of map, so we do.</span></a>
|
||
<a class="sourceLine" id="cb58-4" data-line-number="4"> <span class="fu">==></span> length (not <span class="dt">True</span> <span class="fu">:</span> map not (<span class="dt">False</span><span class="fu">:</span>[]))</a>
|
||
<a class="sourceLine" id="cb58-5" data-line-number="5"> <span class="co">-- Now the argument of length has a (:) we can pattern match on, so we apply the</span></a>
|
||
<a class="sourceLine" id="cb58-6" data-line-number="6"> <span class="co">-- second equation of length</span></a>
|
||
<a class="sourceLine" id="cb58-7" data-line-number="7"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> length (map not (<span class="dt">False</span><span class="fu">:</span>[]))</a>
|
||
<a class="sourceLine" id="cb58-8" data-line-number="8"> <span class="co">-- The outermost function is now +, but it can't do anything unless both arguments</span></a>
|
||
<a class="sourceLine" id="cb58-9" data-line-number="9"> <span class="co">-- are numbers. So we need to evaluate length. In order to pick an equation, we need</span></a>
|
||
<a class="sourceLine" id="cb58-10" data-line-number="10"> <span class="co">-- to evaluate the argument of length again. We apply the second equation of map</span></a>
|
||
<a class="sourceLine" id="cb58-11" data-line-number="11"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> length (not <span class="dt">False</span> <span class="fu">:</span> map not ([]))</a>
|
||
<a class="sourceLine" id="cb58-12" data-line-number="12"> <span class="co">-- Now we can apply the second equation of length again.</span></a>
|
||
<a class="sourceLine" id="cb58-13" data-line-number="13"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">1</span> <span class="fu">+</span> length (map not []))</a>
|
||
<a class="sourceLine" id="cb58-14" data-line-number="14"> <span class="co">-- The outermost + needs a number to be evaluated. The second + also needs a number.</span></a>
|
||
<a class="sourceLine" id="cb58-15" data-line-number="15"> <span class="co">-- We need to evaluate length again, which means we need to pick an equation for length,</span></a>
|
||
<a class="sourceLine" id="cb58-16" data-line-number="16"> <span class="co">-- which means we need to evaluate its argument. This time it is the first equation for</span></a>
|
||
<a class="sourceLine" id="cb58-17" data-line-number="17"> <span class="co">-- map that applies.</span></a>
|
||
<a class="sourceLine" id="cb58-18" data-line-number="18"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">1</span> <span class="fu">+</span> length [])</a>
|
||
<a class="sourceLine" id="cb58-19" data-line-number="19"> <span class="co">-- Now we can apply the first equation for length</span></a>
|
||
<a class="sourceLine" id="cb58-20" data-line-number="20"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">1</span> <span class="fu">+</span> <span class="dv">0</span>)</a>
|
||
<a class="sourceLine" id="cb58-21" data-line-number="21"> <span class="co">-- The outermost + still can't be evaluated, but the inner one can</span></a>
|
||
<a class="sourceLine" id="cb58-22" data-line-number="22"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb58-23" data-line-number="23"> <span class="co">-- Finally we evaluate the outer +</span></a>
|
||
<a class="sourceLine" id="cb58-24" data-line-number="24"> <span class="fu">==></span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>Note that we didn’t need to evaluate any of the <code>not</code> applications.</p>
|
||
<p>Let’s introduce some terminology. We say that pattern matching <em>forces</em> evaluation. When Haskell evaluates something, it evaluates it to something called <em>weak head normal form (WHNF)</em>. WHNF basically means <em>a value that can be pattern matched on</em>. An expression is in WHNF if it can’t be evaluated on <em>its top level</em>. This means it either:</p>
|
||
<ul>
|
||
<li>is a constant, for example: <code>1</code></li>
|
||
<li>has a constructor at the top level, for example: <code>False</code>, <code>Just (1+1)</code>, <code>0:filter f xs</code></li>
|
||
<li>is a function, for example: <code>(\x -> 1+x)</code></li>
|
||
</ul>
|
||
<p>The most notable class of expressions that is <em>not</em> in WHNF is function applications. If an expression consists of a function (that is not a constructor), applied to some arguments, it is not in WHNF. We must evaluate it in order to get something pattern matchable.</p>
|
||
<p>In the previous example we couldn’t evaluate <code>length (map not (False:[]))</code> at the top level because the argument to <code>length</code> wasn’t in WHNF. When we apply the second equation of <code>map</code>, we get <code>length (not False : map not [])</code>, and now the argument to length is in WHNF since there is a constructor, <code>(:)</code>, at the top level. This is a bit more evident if we switch from infix to prefix notation and write the argument to <code>length</code> as <code>(:) (not False) (map not [])</code>.</p>
|
||
<p>In practice, pattern matching is not the only thing that forces evaluation. Primitives like <code>(+)</code> also force their arguments.</p>
|
||
<p>Instead of forcing, some sources talk about <em>strictness</em>, we can say for instance that <code>(+)</code> is <em>strict in both arguments</em>.</p>
|
||
<h3 id="a-word-about-sharing"><span class="header-section-number">10.4.2</span> A Word About Sharing</h3>
|
||
<p>There’s one more thing about Haskell evaluation. Any time you give a value a <em>name</em>, it gets <em>shared</em>. This means that every occurrence of the name points at the same (potentially unevaluated) expression. When the expression gets evaluated, all occurrences of the name see the result.</p>
|
||
<p>Let’s look at a very simple example.</p>
|
||
<div class="sourceCode" id="cb59"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb59-1" data-line-number="1">square x <span class="fu">=</span> x<span class="fu">*</span>x</a></code></pre></div>
|
||
<p>Based on the previous sections, you might imagine evaluation works like the following. The evaluation is first represented textually, and then visually, as an expression tree.</p>
|
||
<div class="sourceCode" id="cb60"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb60-1" data-line-number="1">square (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb60-2" data-line-number="2"> <span class="fu">==></span> (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>) <span class="fu">*</span> (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>) <span class="co">-- definition of square</span></a>
|
||
<a class="sourceLine" id="cb60-3" data-line-number="3"> <span class="fu">==></span> <span class="dv">4</span> <span class="fu">*</span> (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>) <span class="co">-- (*) forces left argument</span></a>
|
||
<a class="sourceLine" id="cb60-4" data-line-number="4"> <span class="fu">==></span> <span class="dv">4</span> <span class="fu">*</span> <span class="dv">4</span> <span class="co">-- (*) forces right argument</span></a>
|
||
<a class="sourceLine" id="cb60-5" data-line-number="5"> <span class="fu">==></span> <span class="dv">16</span> <span class="co">-- definition of (*)</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb61"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb61-1" data-line-number="1">square <span class="fu">==></span> <span class="fu">*</span> <span class="fu">==></span> <span class="fu">*</span> <span class="fu">==></span> <span class="fu">*</span> <span class="fu">==></span> <span class="dv">16</span></a>
|
||
<a class="sourceLine" id="cb61-2" data-line-number="2"> <span class="fu">|</span> <span class="fu">/</span> \ <span class="fu">/</span> \ <span class="fu">/</span> \</a>
|
||
<a class="sourceLine" id="cb61-3" data-line-number="3"> <span class="fu">+</span> <span class="fu">+</span> <span class="fu">+</span> <span class="dv">4</span> <span class="fu">+</span> <span class="dv">4</span> <span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb61-4" data-line-number="4"> <span class="fu">/</span> \ <span class="fu">/</span> \ <span class="fu">/</span> \ <span class="fu">/</span> \</a>
|
||
<a class="sourceLine" id="cb61-5" data-line-number="5"><span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>However, what really happens is that the expression <code>2+2</code> named by the variable <code>x</code> is only computed once. The result of the evaluation is then shared between the two occurrences of <code>x</code> inside <code>square</code>. So here’s the correct evaluation, first textually, and then visually. Note how now instead of an expression tree, we have an <em>expression graph</em>. This is why Haskell evaluation is sometimes called <a href="https://en.wikipedia.org/wiki/Graph_reduction"><em>graph reduction</em></a>.</p>
|
||
<div class="sourceCode" id="cb62"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb62-1" data-line-number="1">square (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb62-2" data-line-number="2"> <span class="fu">==></span> (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>) <span class="fu">*</span> (<span class="dv">2</span><span class="fu">+</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb62-3" data-line-number="3"> <span class="fu">==></span> <span class="dv">4</span> <span class="fu">*</span> <span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb62-4" data-line-number="4"> <span class="fu">==></span> <span class="dv">16</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb63"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb63-1" data-line-number="1">square <span class="fu">==></span> <span class="fu">*</span> <span class="fu">==></span> <span class="fu">*</span> <span class="fu">==></span> <span class="dv">16</span></a>
|
||
<a class="sourceLine" id="cb63-2" data-line-number="2"> <span class="fu">|</span> <span class="fu">/</span> \ <span class="fu">/</span> \</a>
|
||
<a class="sourceLine" id="cb63-3" data-line-number="3"> <span class="fu">|</span> \ <span class="fu">/</span> \ <span class="fu">/</span></a>
|
||
<a class="sourceLine" id="cb63-4" data-line-number="4"> <span class="fu">+</span> <span class="fu">+</span> <span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb63-5" data-line-number="5"> <span class="fu">/</span> \ <span class="fu">/</span> \</a>
|
||
<a class="sourceLine" id="cb63-6" data-line-number="6"><span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>As another example, consider the function <code>f</code> below and its evaluation.</p>
|
||
<div class="sourceCode" id="cb64"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb64-1" data-line-number="1"><span class="ot">f ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb64-2" data-line-number="2">f i <span class="fu">=</span> <span class="kw">if</span> i<span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> i</a></code></pre></div>
|
||
<div class="sourceCode" id="cb65"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb65-1" data-line-number="1"> _______shared________</a>
|
||
<a class="sourceLine" id="cb65-2" data-line-number="2"> <span class="fu">|</span> <span class="fu">|</span></a>
|
||
<a class="sourceLine" id="cb65-3" data-line-number="3">f (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>) <span class="fu">==></span> <span class="kw">if</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb65-4" data-line-number="4"> <span class="fu">==></span> <span class="kw">if</span> <span class="dv">2</span><span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb65-5" data-line-number="5"> <span class="fu">==></span> <span class="kw">if</span> <span class="dt">False</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb65-6" data-line-number="6"> <span class="fu">==></span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>Haskell does not compute <code>1+1</code> twice because it was named, and the name was used twice. We can contrast this with another function that takes two arguments:</p>
|
||
<div class="sourceCode" id="cb66"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb66-1" data-line-number="1"><span class="ot">g ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb66-2" data-line-number="2">g i j <span class="fu">=</span> <span class="kw">if</span> i<span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> j</a></code></pre></div>
|
||
<div class="sourceCode" id="cb67"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb67-1" data-line-number="1"> ______no sharing_____</a>
|
||
<a class="sourceLine" id="cb67-2" data-line-number="2"> <span class="fu">|</span> <span class="fu">|</span></a>
|
||
<a class="sourceLine" id="cb67-3" data-line-number="3">g (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>) (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>) <span class="fu">==></span> <span class="kw">if</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb67-4" data-line-number="4"> <span class="fu">==></span> <span class="kw">if</span> <span class="dv">2</span><span class="fu">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb67-5" data-line-number="5"> <span class="fu">==></span> <span class="kw">if</span> <span class="dt">False</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb67-6" data-line-number="6"> <span class="fu">==></span> (<span class="dv">1</span><span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb67-7" data-line-number="7"> <span class="fu">==></span> <span class="dv">2</span></a></code></pre></div>
|
||
<p>Here we have two different names for equivalent expressions, and Haskell doesn’t magically share them. Automatically sharing equivalent expressions is an optimization called <em>Common Subexpression Elimination (CSE)</em>. You can learn a bit more <a href="https://wiki.haskell.org/GHC_optimisations#Common_subexpression_elimination">CSE and Haskell here</a>.</p>
|
||
<p>You can name things via</p>
|
||
<ul>
|
||
<li>Function arguments</li>
|
||
<li><code>let ... in ...</code></li>
|
||
<li><code>where</code></li>
|
||
</ul>
|
||
<p>Combined with laziness, sharing means that <em>a name gets evaluated at most once</em>.</p>
|
||
<h3 id="further-examples"><span class="header-section-number">10.4.3</span> Further Examples</h3>
|
||
<p>You’ll find below a slightly contrived recursive definition of the function <code>even</code>. It will illustrate the concepts of forcing and sharing.</p>
|
||
<div class="sourceCode" id="cb68"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb68-1" data-line-number="1">not<span class="ot"> ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb68-2" data-line-number="2">not <span class="dt">True</span> <span class="fu">=</span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb68-3" data-line-number="3">not <span class="dt">False</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb68-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb68-5" data-line-number="5"><span class="ot">(||) ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb68-6" data-line-number="6"><span class="dt">True</span> <span class="fu">||</span> _ <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb68-7" data-line-number="7">_ <span class="fu">||</span> x <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb68-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb68-9" data-line-number="9">even<span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb68-10" data-line-number="10">even x <span class="fu">=</span> x <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even (x<span class="fu">-</span><span class="dv">1</span>))</a></code></pre></div>
|
||
<p>Firstly, note that <code>||</code> forces its left argument, but not its right argument. (In other words, <code>||</code> is <em>strict in its left argument</em>.) This is because we only need to evaluate the left argument of <code>||</code> in order to know which equation applies. This means by extension that <code>even</code> forces its first argument:</p>
|
||
<ul>
|
||
<li><code>||</code> forces <code>x==0</code></li>
|
||
<li><code>x==0</code> forces <code>x</code></li>
|
||
</ul>
|
||
<p>Now let’s evaluate the expression <code>even 2</code> to WHNF.</p>
|
||
<div class="sourceCode" id="cb69"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb69-1" data-line-number="1">even <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb69-2" data-line-number="2"><span class="fu">==></span> <span class="dv">2</span> <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even (<span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>)) <span class="co">-- apply definition of even</span></a>
|
||
<a class="sourceLine" id="cb69-3" data-line-number="3"><span class="fu">==></span> <span class="dt">False</span> <span class="fu">||</span> not (even (<span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>)) <span class="co">-- || forces its first argument</span></a>
|
||
<a class="sourceLine" id="cb69-4" data-line-number="4"><span class="fu">==></span> not (even (<span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>)) <span class="co">-- second equation of ||</span></a>
|
||
<a class="sourceLine" id="cb69-5" data-line-number="5"><span class="fu">==></span> not ((<span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>) <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even ((<span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>)<span class="fu">-</span><span class="dv">1</span>))) <span class="co">-- not forces its argument: apply definition of even</span></a>
|
||
<a class="sourceLine" id="cb69-6" data-line-number="6"><span class="fu">==></span> not ( <span class="dv">1</span> <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even ( <span class="dv">1</span> <span class="fu">-</span><span class="dv">1</span>))) <span class="co">-- note sharing!</span></a>
|
||
<a class="sourceLine" id="cb69-7" data-line-number="7"><span class="fu">==></span> not ( <span class="dt">False</span> <span class="fu">||</span> not (even (<span class="dv">1</span><span class="fu">-</span><span class="dv">1</span>)))</a>
|
||
<a class="sourceLine" id="cb69-8" data-line-number="8"><span class="fu">==></span> not (not (even (<span class="dv">1</span><span class="fu">-</span><span class="dv">1</span>)))</a>
|
||
<a class="sourceLine" id="cb69-9" data-line-number="9"><span class="fu">==></span> not (not ((<span class="dv">1</span><span class="fu">-</span><span class="dv">1</span>) <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even ((<span class="dv">1</span><span class="fu">-</span><span class="dv">1</span>)<span class="fu">-</span><span class="dv">1</span>))))</a>
|
||
<a class="sourceLine" id="cb69-10" data-line-number="10"><span class="fu">==></span> not (not ( <span class="dv">0</span> <span class="fu">==</span> <span class="dv">0</span> <span class="fu">||</span> not (even ( <span class="dv">0</span> <span class="fu">-</span><span class="dv">1</span>)))) <span class="co">-- (sharing)</span></a>
|
||
<a class="sourceLine" id="cb69-11" data-line-number="11"><span class="fu">==></span> not (not ( <span class="dt">True</span> <span class="fu">||</span> not (even (<span class="dv">0</span><span class="fu">-</span><span class="dv">1</span>))))</a>
|
||
<a class="sourceLine" id="cb69-12" data-line-number="12"><span class="fu">==></span> not (not <span class="dt">True</span>)</a>
|
||
<a class="sourceLine" id="cb69-13" data-line-number="13"><span class="fu">==></span> not <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb69-14" data-line-number="14"><span class="fu">==></span> <span class="dt">True</span></a></code></pre></div>
|
||
<p>Note that with this alternate definition <code>even</code> would not have worked. Can you tell why?</p>
|
||
<div class="sourceCode" id="cb70"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb70-1" data-line-number="1">even' x <span class="fu">=</span> not (even' (x<span class="fu">-</span><span class="dv">1</span>)) <span class="fu">||</span> x <span class="fu">==</span> <span class="dv">0</span></a></code></pre></div>
|
||
<p>Now we can really understand what’s going on in the infinite list example from earlier. Let’s use these definitions:</p>
|
||
<div class="sourceCode" id="cb71"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb71-1" data-line-number="1">head (x<span class="fu">:</span>_) <span class="fu">=</span> x</a>
|
||
<a class="sourceLine" id="cb71-2" data-line-number="2">head [] <span class="fu">=</span> <span class="fu">-</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb71-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb71-4" data-line-number="4">filter p [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb71-5" data-line-number="5">filter p (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">if</span> p x</a>
|
||
<a class="sourceLine" id="cb71-6" data-line-number="6"> <span class="kw">then</span> x <span class="fu">:</span> filter p xs</a>
|
||
<a class="sourceLine" id="cb71-7" data-line-number="7"> <span class="kw">else</span> filter p xs</a>
|
||
<a class="sourceLine" id="cb71-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb71-9" data-line-number="9">map f [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb71-10" data-line-number="10">map f (x<span class="fu">:</span>xs) <span class="fu">=</span> f x <span class="fu">:</span> map f xs</a>
|
||
<a class="sourceLine" id="cb71-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb71-12" data-line-number="12"><span class="co">-- [0..] is syntax sugar for enumFrom 0</span></a>
|
||
<a class="sourceLine" id="cb71-13" data-line-number="13">enumFrom n <span class="fu">=</span> n <span class="fu">:</span> enumFrom (n<span class="fu">+</span><span class="dv">1</span>)</a></code></pre></div>
|
||
<p>And here we go:</p>
|
||
<div class="sourceCode" id="cb72"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb72-1" data-line-number="1"> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-2" data-line-number="2"><span class="fu">===</span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) (enumFrom <span class="dv">0</span>)))</a>
|
||
<a class="sourceLine" id="cb72-3" data-line-number="3"><span class="co">-- head forces filter, which forces map, which forces enumFrom. We apply the definition of enumFrom.</span></a>
|
||
<a class="sourceLine" id="cb72-4" data-line-number="4"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) (<span class="dv">0</span><span class="fu">:</span>[<span class="dv">1</span><span class="fu">..</span>])))</a>
|
||
<a class="sourceLine" id="cb72-5" data-line-number="5"><span class="co">-- head forces filter, which forces map. We apply the second equation of map.</span></a>
|
||
<a class="sourceLine" id="cb72-6" data-line-number="6"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) ((<span class="dv">3</span><span class="fu">^</span><span class="dv">0</span>) <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-7" data-line-number="7"><span class="co">-- head forces filter. We apply the second equation of filter</span></a>
|
||
<a class="sourceLine" id="cb72-8" data-line-number="8"><span class="fu">==></span> head (<span class="kw">if</span> ((<span class="dv">3</span><span class="fu">^</span><span class="dv">0</span>)<span class="fu">></span><span class="dv">100</span>)</a>
|
||
<a class="sourceLine" id="cb72-9" data-line-number="9"> <span class="kw">then</span> (<span class="dv">3</span><span class="fu">^</span><span class="dv">0</span>) <span class="fu">:</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>])</a>
|
||
<a class="sourceLine" id="cb72-10" data-line-number="10"> <span class="kw">else</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-11" data-line-number="11"><span class="co">-- head forces if, if forces >, > forces ^. Note sharing!</span></a>
|
||
<a class="sourceLine" id="cb72-12" data-line-number="12"><span class="fu">==></span> head (<span class="kw">if</span> (<span class="dv">1</span><span class="fu">></span><span class="dv">100</span>)</a>
|
||
<a class="sourceLine" id="cb72-13" data-line-number="13"> <span class="kw">then</span> <span class="dv">1</span> <span class="fu">:</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>])</a>
|
||
<a class="sourceLine" id="cb72-14" data-line-number="14"> <span class="kw">else</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-15" data-line-number="15"><span class="co">-- head forces if, if forces ></span></a>
|
||
<a class="sourceLine" id="cb72-16" data-line-number="16"><span class="fu">==></span> head (<span class="kw">if</span> <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb72-17" data-line-number="17"> <span class="kw">then</span> <span class="dv">1</span> <span class="fu">:</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>])</a>
|
||
<a class="sourceLine" id="cb72-18" data-line-number="18"> <span class="kw">else</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-19" data-line-number="19"><span class="co">-- apply definition of if</span></a>
|
||
<a class="sourceLine" id="cb72-20" data-line-number="20"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">1</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-21" data-line-number="21"><span class="co">-- let's take slightly bigger steps now</span></a>
|
||
<a class="sourceLine" id="cb72-22" data-line-number="22"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) (<span class="dv">1</span><span class="fu">:</span>[<span class="dv">2</span><span class="fu">..</span>])))</a>
|
||
<a class="sourceLine" id="cb72-23" data-line-number="23"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) ((<span class="dv">3</span><span class="fu">^</span><span class="dv">1</span>) <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">2</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-24" data-line-number="24"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">3</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">2</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-25" data-line-number="25"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">2</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-26" data-line-number="26"><span class="co">-- and even bigger steps now</span></a>
|
||
<a class="sourceLine" id="cb72-27" data-line-number="27"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">9</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">3</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-28" data-line-number="28"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">27</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">4</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-29" data-line-number="29"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">81</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">5</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-30" data-line-number="30"><span class="fu">==></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (<span class="dv">243</span> <span class="fu">:</span> map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">6</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-31" data-line-number="31"><span class="fu">==></span> head (<span class="dv">243</span> <span class="fu">:</span> filter (<span class="fu">></span><span class="dv">100</span>) (map (<span class="dv">3</span><span class="fu">^</span>) [<span class="dv">6</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb72-32" data-line-number="32"><span class="fu">==></span> <span class="dv">243</span></a></code></pre></div>
|
||
<p>Whew.</p>
|
||
<h2 id="working-with-infinite-lists"><span class="header-section-number">10.5</span> Working with Infinite Lists</h2>
|
||
<p>Functions that work with lists often have the best performance when they’re written in such a way that they utilize laziness. One way to try to accomplish this is to write list-handling functions that work well with infinite lists.</p>
|
||
<p>To write a function that transforms an infinite list, you need to write a function that only looks at a limited prefix of the input list, then outputs a <code>(:)</code> constructor, and then recurses. Here’s a first example.</p>
|
||
<div class="sourceCode" id="cb73"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb73-1" data-line-number="1"><span class="ot">everySecond ::</span> [a] <span class="ot">-></span> [a]</a>
|
||
<a class="sourceLine" id="cb73-2" data-line-number="2">everySecond [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb73-3" data-line-number="3">everySecond (x<span class="fu">:</span>y<span class="fu">:</span>xs) <span class="fu">=</span> x <span class="fu">:</span> everySecond xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb74"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb74-1" data-line-number="1">take <span class="dv">10</span> (everySecond [<span class="dv">0</span><span class="fu">..</span>]) <span class="fu">==></span> [<span class="dv">0</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>,<span class="dv">8</span>,<span class="dv">10</span>,<span class="dv">12</span>,<span class="dv">14</span>,<span class="dv">16</span>,<span class="dv">18</span>]</a></code></pre></div>
|
||
<p>A good heuristic for writing functions that work well with infinite lists is: can the <code>head</code> of the result be evaluated cheaply? Here are two examples of functions that don’t work with infinite inputs. In the case of <code>mapTailRecursive</code>, the problem is that it needs to process the whole input before being in WHNF. In the case of <code>myDrop</code>, the problem is that it uses the function <code>length</code>, doesn’t work for infinite lists since it tries to iterate until the end of the list.</p>
|
||
<div class="sourceCode" id="cb75"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb75-1" data-line-number="1">map<span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</a>
|
||
<a class="sourceLine" id="cb75-2" data-line-number="2">map _ [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb75-3" data-line-number="3">map f (x<span class="fu">:</span>xs) <span class="fu">=</span> f x <span class="fu">:</span> map f xs</a>
|
||
<a class="sourceLine" id="cb75-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb75-5" data-line-number="5"><span class="ot">mapTailRecursive ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</a>
|
||
<a class="sourceLine" id="cb75-6" data-line-number="6">mapTailRecursive f xs <span class="fu">=</span> go xs []</a>
|
||
<a class="sourceLine" id="cb75-7" data-line-number="7"> <span class="kw">where</span> go (x<span class="fu">:</span>xs) res <span class="fu">=</span> go xs (res<span class="fu">++</span>[f x])</a>
|
||
<a class="sourceLine" id="cb75-8" data-line-number="8"> go [] res <span class="fu">=</span> res</a></code></pre></div>
|
||
<div class="sourceCode" id="cb76"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb76-1" data-line-number="1">head (map inc [<span class="dv">0</span><span class="fu">..</span>]) <span class="fu">==></span> head (inc <span class="dv">0</span> <span class="fu">:</span> map inc [<span class="dv">1</span><span class="fu">..</span>]) <span class="fu">==></span> inc <span class="dv">0</span> <span class="fu">==></span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb76-2" data-line-number="2">head (mapTailRecursive inc [<span class="dv">0</span><span class="fu">..</span>])</a>
|
||
<a class="sourceLine" id="cb76-3" data-line-number="3"> <span class="fu">==></span> head (go [<span class="dv">0</span><span class="fu">..</span>] [])</a>
|
||
<a class="sourceLine" id="cb76-4" data-line-number="4"> <span class="fu">==></span> head (go [<span class="dv">1</span><span class="fu">..</span>] ([]<span class="fu">++</span>[inc <span class="dv">0</span>]))</a>
|
||
<a class="sourceLine" id="cb76-5" data-line-number="5"> <span class="fu">==></span> head (go [<span class="dv">2</span><span class="fu">..</span>] ([]<span class="fu">++</span>[inc <span class="dv">0</span>]<span class="fu">++</span>[inc <span class="dv">1</span>]))</a>
|
||
<a class="sourceLine" id="cb76-6" data-line-number="6"> <span class="fu">==></span> head (go [<span class="dv">3</span><span class="fu">..</span>] ([]<span class="fu">++</span>[inc <span class="dv">0</span>]<span class="fu">++</span>[inc <span class="dv">1</span>]<span class="fu">++</span>[inc <span class="dv">2</span>]))</a>
|
||
<a class="sourceLine" id="cb76-7" data-line-number="7"> <span class="co">-- never terminates</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb77"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb77-1" data-line-number="1">drop<span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> [a]</a>
|
||
<a class="sourceLine" id="cb77-2" data-line-number="2">drop <span class="dv">0</span> xs <span class="fu">=</span> xs</a>
|
||
<a class="sourceLine" id="cb77-3" data-line-number="3">drop _ [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb77-4" data-line-number="4">drop n (x<span class="fu">:</span>xs) <span class="fu">=</span> drop (n<span class="fu">-</span><span class="dv">1</span>) xs</a>
|
||
<a class="sourceLine" id="cb77-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb77-6" data-line-number="6"><span class="ot">myDrop ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> [a]</a>
|
||
<a class="sourceLine" id="cb77-7" data-line-number="7">myDrop <span class="dv">0</span> xs <span class="fu">=</span> xs</a>
|
||
<a class="sourceLine" id="cb77-8" data-line-number="8">myDrop n xs <span class="fu">=</span> <span class="kw">if</span> n <span class="fu">></span> length xs <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="fu">-</span><span class="dv">1</span>) (tail xs)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb78"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb78-1" data-line-number="1">head (drop <span class="dv">2</span> [<span class="dv">0</span><span class="fu">..</span>]) <span class="fu">==></span> head (drop <span class="dv">1</span> [<span class="dv">1</span><span class="fu">..</span>]) <span class="fu">==></span> head (drop <span class="dv">0</span> [<span class="dv">2</span><span class="fu">..</span>]) <span class="fu">==></span> head [<span class="dv">2</span><span class="fu">..</span>] <span class="fu">==></span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb78-2" data-line-number="2">head (myDrop <span class="dv">2</span> [<span class="dv">0</span><span class="fu">..</span>])</a>
|
||
<a class="sourceLine" id="cb78-3" data-line-number="3"> <span class="fu">==></span> head (<span class="kw">if</span> n <span class="fu">></span> length [<span class="dv">0</span><span class="fu">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="fu">-</span><span class="dv">1</span>) (tail [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb78-4" data-line-number="4"> <span class="fu">==></span> head (<span class="kw">if</span> n <span class="fu">></span> <span class="dv">1</span><span class="fu">+</span>length [<span class="dv">1</span><span class="fu">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="fu">-</span><span class="dv">1</span>) (tail [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb78-5" data-line-number="5"> <span class="fu">==></span> head (<span class="kw">if</span> n <span class="fu">></span> <span class="dv">1</span><span class="fu">+</span><span class="dv">1</span><span class="fu">+</span>length [<span class="dv">2</span><span class="fu">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="fu">-</span><span class="dv">1</span>) (tail [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb78-6" data-line-number="6"> <span class="fu">==></span> head (<span class="kw">if</span> n <span class="fu">></span> <span class="dv">1</span><span class="fu">+</span><span class="dv">1</span><span class="fu">+</span><span class="dv">1</span><span class="fu">+</span>length [<span class="dv">3</span><span class="fu">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="fu">-</span><span class="dv">1</span>) (tail [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb78-7" data-line-number="7"> <span class="co">-- never terminates</span></a></code></pre></div>
|
||
<p>Pretty much all the list functions in the standard library are written in this form, for example:</p>
|
||
<div class="sourceCode" id="cb79"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb79-1" data-line-number="1">head (takeWhile (<span class="fu">>=</span><span class="dv">0</span>) [<span class="dv">0</span><span class="fu">..</span>]) <span class="fu">==></span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb79-2" data-line-number="2">head (concat (repeat [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])) <span class="fu">==></span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb79-3" data-line-number="3">head (zip [<span class="dv">0</span><span class="fu">..</span>] [<span class="dv">2</span><span class="fu">..</span>]) <span class="fu">==></span> (<span class="dv">0</span>,<span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb79-4" data-line-number="4">head (filter even [<span class="dv">3</span><span class="fu">..</span>]) <span class="fu">==></span> <span class="dv">4</span></a></code></pre></div>
|
||
<h2 id="interlude-adding-strictness"><span class="header-section-number">10.6</span> Interlude: Adding Strictness</h2>
|
||
<p>Remember <code>foldr</code> from part 1? Let’s have a look at its cousin <code>foldl</code>. Here’s the definition of <code>foldl</code> for lists (it’s actually part of the <code>Foldable</code> typeclass and so works for various other types too). While <code>foldr</code> processes a list right-to-left, <code>foldl</code> processes a list left-to-right. To be a bit more exact, <code>foldr</code> <em>associates to the right</em> while <code>foldl</code> <em>associates to the left</em>. Note the difference in the next example:</p>
|
||
<div class="sourceCode" id="cb80"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb80-1" data-line-number="1">foldr (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> <span class="dv">1</span><span class="fu">+</span>(<span class="dv">2</span><span class="fu">+</span>(<span class="dv">3</span><span class="fu">+</span><span class="dv">0</span>))</a>
|
||
<a class="sourceLine" id="cb80-2" data-line-number="2">foldl (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> ((<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">+</span><span class="dv">2</span>)<span class="fu">+</span><span class="dv">3</span></a></code></pre></div>
|
||
<p>Here are the definitions of <code>foldl</code> and <code>foldr</code>:</p>
|
||
<div class="sourceCode" id="cb81"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb81-1" data-line-number="1">foldl<span class="ot"> ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> [b] <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb81-2" data-line-number="2">foldl f z [] <span class="fu">=</span> z</a>
|
||
<a class="sourceLine" id="cb81-3" data-line-number="3">foldl f z (x<span class="fu">:</span>xs) <span class="fu">=</span> foldl f (f z x) xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb82"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb82-1" data-line-number="1">foldr<span class="ot"> ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> b) <span class="ot">-></span> b <span class="ot">-></span> [a] <span class="ot">-></span> b</a>
|
||
<a class="sourceLine" id="cb82-2" data-line-number="2">foldr f y [] <span class="fu">=</span> y</a>
|
||
<a class="sourceLine" id="cb82-3" data-line-number="3">foldr f y (x<span class="fu">:</span>xs) <span class="fu">=</span> f x (foldr f y xs)</a></code></pre></div>
|
||
<p>As <code>foldr f y (x:xs) ==> f x (foldr f y xs)</code>, it enables lazy evaluation to focus on <code>f</code> on the second step. Hence, <code>foldr</code> works nicely with lazy or short-circuiting operations:</p>
|
||
<div class="sourceCode" id="cb83"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb83-1" data-line-number="1"> foldr (<span class="fu">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>,<span class="dt">False</span>]</a>
|
||
<a class="sourceLine" id="cb83-2" data-line-number="2"><span class="fu">==></span> <span class="dt">False</span> <span class="fu">&&</span> (foldr (<span class="fu">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>])</a>
|
||
<a class="sourceLine" id="cb83-3" data-line-number="3"><span class="fu">==></span> <span class="dt">False</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb84"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb84-1" data-line-number="1"> head (foldr (<span class="fu">++</span>) [] [<span class="st">"Hello"</span>,<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</a>
|
||
<a class="sourceLine" id="cb84-2" data-line-number="2"><span class="fu">==></span> head (<span class="st">"Hello"</span> <span class="fu">++</span> (foldr (<span class="fu">++</span>) [] [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>]))</a>
|
||
<a class="sourceLine" id="cb84-3" data-line-number="3"><span class="fu">==></span> head (<span class="ch">'H'</span><span class="fu">:</span>(<span class="st">"ello"</span> <span class="fu">++</span> (foldr (<span class="fu">++</span>) [] [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])))</a>
|
||
<a class="sourceLine" id="cb84-4" data-line-number="4"><span class="fu">==></span> <span class="ch">'H'</span></a></code></pre></div>
|
||
<p>However <code>foldl</code> needs to process the whole list in order to produce a (WHNF) value. The reason is that <code>foldl</code> remains in the leftmost-outermost position for as long as its list argument remains non-empty. This makes <code>foldl</code> the priority for lazy evaluation. Only after the list becomes empty does the evaluation proceed into simplifying the folded values.</p>
|
||
<div class="sourceCode" id="cb85"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb85-1" data-line-number="1"> foldl (<span class="fu">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>,<span class="dt">False</span>]</a>
|
||
<a class="sourceLine" id="cb85-2" data-line-number="2"><span class="fu">==></span> foldl (<span class="fu">&&</span>) (<span class="dt">True</span><span class="fu">&&</span><span class="dt">False</span>) [<span class="dt">False</span>,<span class="dt">False</span>]</a>
|
||
<a class="sourceLine" id="cb85-3" data-line-number="3"><span class="fu">==></span> foldl (<span class="fu">&&</span>) ((<span class="dt">True</span><span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span>) [<span class="dt">False</span>]</a>
|
||
<a class="sourceLine" id="cb85-4" data-line-number="4"><span class="fu">==></span> foldl (<span class="fu">&&</span>) (((<span class="dt">True</span><span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span>) []</a>
|
||
<a class="sourceLine" id="cb85-5" data-line-number="5"><span class="fu">==></span> ((<span class="dt">True</span><span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb85-6" data-line-number="6"><span class="fu">==></span> ( <span class="dt">False</span> <span class="fu">&&</span><span class="dt">False</span>)<span class="fu">&&</span><span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb85-7" data-line-number="7"><span class="fu">==></span> <span class="dt">False</span> <span class="fu">&&</span><span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb85-8" data-line-number="8"><span class="fu">==></span> <span class="dt">False</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb86"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb86-1" data-line-number="1"> head (foldl (<span class="fu">++</span>) [] [<span class="st">"Hello"</span>,<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</a>
|
||
<a class="sourceLine" id="cb86-2" data-line-number="2"><span class="fu">==></span> head (foldl (<span class="fu">++</span>) ([]<span class="fu">++</span><span class="st">"Hello"</span>) [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</a>
|
||
<a class="sourceLine" id="cb86-3" data-line-number="3"><span class="fu">==></span> head (foldl (<span class="fu">++</span>) (([]<span class="fu">++</span><span class="st">"Hello"</span>)<span class="fu">++</span><span class="st">"World"</span>) [<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</a>
|
||
<a class="sourceLine" id="cb86-4" data-line-number="4"><span class="fu">==></span> head (foldl (<span class="fu">++</span>) ((([]<span class="fu">++</span><span class="st">"Hello"</span>)<span class="fu">++</span><span class="st">"World"</span>)<span class="fu">++</span><span class="st">"lorem"</span>) [<span class="st">"ipsum"</span>])</a>
|
||
<a class="sourceLine" id="cb86-5" data-line-number="5"><span class="fu">==></span> head (foldl (<span class="fu">++</span>) (((([]<span class="fu">++</span><span class="st">"Hello"</span>)<span class="fu">++</span><span class="st">"World"</span>)<span class="fu">++</span><span class="st">"lorem"</span>)<span class="fu">++</span><span class="st">"ipsum"</span>) [])</a>
|
||
<a class="sourceLine" id="cb86-6" data-line-number="6"><span class="fu">==></span> head (((([]<span class="fu">++</span><span class="st">"Hello"</span>)<span class="fu">++</span><span class="st">"World"</span>)<span class="fu">++</span><span class="st">"lorem"</span>)<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-7" data-line-number="7"><span class="co">-- head forces the last ++, which forces the next-to-last ++, and so on</span></a>
|
||
<a class="sourceLine" id="cb86-8" data-line-number="8"><span class="fu">==></span> head (((<span class="st">"Hello"</span><span class="fu">++</span><span class="st">"World"</span>)<span class="fu">++</span><span class="st">"lorem"</span>)<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-9" data-line-number="9"><span class="co">-- same happens again</span></a>
|
||
<a class="sourceLine" id="cb86-10" data-line-number="10"><span class="fu">==></span> head (((<span class="ch">'H'</span><span class="fu">:</span>(<span class="st">"ello"</span><span class="fu">++</span><span class="st">"World"</span>))<span class="fu">++</span><span class="st">"lorem"</span>)<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-11" data-line-number="11"><span class="co">-- for clarity, let's drop the "ello"++"World" expression which isn't needed</span></a>
|
||
<a class="sourceLine" id="cb86-12" data-line-number="12"><span class="fu">==></span> head (((<span class="ch">'H'</span><span class="fu">:</span>__)<span class="fu">++</span><span class="st">"lorem"</span>)<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-13" data-line-number="13"><span class="co">-- now the next-to-last ++ can operate</span></a>
|
||
<a class="sourceLine" id="cb86-14" data-line-number="14"><span class="fu">==></span> head ((<span class="ch">'H'</span><span class="fu">:</span>(__<span class="fu">++</span><span class="st">"lorem"</span>))<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-15" data-line-number="15"><span class="co">-- let's drop the __++"lorem" expression</span></a>
|
||
<a class="sourceLine" id="cb86-16" data-line-number="16"><span class="fu">==></span> head ((<span class="ch">'H'</span><span class="fu">:</span>__)<span class="fu">++</span><span class="st">"ipsum"</span>)</a>
|
||
<a class="sourceLine" id="cb86-17" data-line-number="17"><span class="co">-- now the last ++ can operate</span></a>
|
||
<a class="sourceLine" id="cb86-18" data-line-number="18"><span class="fu">==></span> head (<span class="ch">'H'</span><span class="fu">:</span>(__<span class="fu">++</span><span class="st">"ipsum"</span>))</a>
|
||
<a class="sourceLine" id="cb86-19" data-line-number="19"><span class="fu">==></span> <span class="ch">'H'</span></a></code></pre></div>
|
||
<p>So why use <code>foldl</code> at all? Let’s return to our first fold example again. Now, since <code>+</code> is a strict operation, both types of fold need to build up an expression with lots of <code>+</code>s. The Haskell implementation needs to track this expression in memory, which is why a problem like this is called a <em>space leak</em>.</p>
|
||
<div class="sourceCode" id="cb87"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb87-1" data-line-number="1"> foldr (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb87-2" data-line-number="2"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> foldr (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb87-3" data-line-number="3"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">2</span> <span class="fu">+</span> foldr (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">3</span>])</a>
|
||
<a class="sourceLine" id="cb87-4" data-line-number="4"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">2</span> <span class="fu">+</span> (<span class="dv">3</span> <span class="fu">+</span> foldr (<span class="fu">+</span>) <span class="dv">0</span> []))</a>
|
||
<a class="sourceLine" id="cb87-5" data-line-number="5"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">2</span> <span class="fu">+</span> (<span class="dv">3</span> <span class="fu">+</span> <span class="dv">0</span>))</a>
|
||
<a class="sourceLine" id="cb87-6" data-line-number="6"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> (<span class="dv">2</span> <span class="fu">+</span> <span class="dv">3</span>)</a>
|
||
<a class="sourceLine" id="cb87-7" data-line-number="7"><span class="fu">==></span> <span class="dv">1</span> <span class="fu">+</span> <span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb87-8" data-line-number="8"><span class="fu">==></span> <span class="dv">6</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb88"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb88-1" data-line-number="1"> foldl (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb88-2" data-line-number="2"><span class="fu">==></span> foldl (<span class="fu">+</span>) (<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb88-3" data-line-number="3"><span class="fu">==></span> foldl (<span class="fu">+</span>) ((<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb88-4" data-line-number="4"><span class="fu">==></span> foldl (<span class="fu">+</span>) (((<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">+</span><span class="dv">2</span>)<span class="fu">+</span><span class="dv">3</span>) []</a>
|
||
<a class="sourceLine" id="cb88-5" data-line-number="5"><span class="fu">==></span> ((<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>)<span class="fu">+</span><span class="dv">2</span>)<span class="fu">+</span><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb88-6" data-line-number="6"><span class="fu">==></span> ( <span class="dv">1</span> <span class="fu">+</span><span class="dv">2</span>)<span class="fu">+</span><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb88-7" data-line-number="7"><span class="fu">==></span> <span class="dv">3</span> <span class="fu">+</span><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb88-8" data-line-number="8"><span class="fu">==></span> <span class="dv">6</span></a></code></pre></div>
|
||
<p>Now let’s instead look at what happens when we use <code>foldl'</code>, a version of <code>foldl</code> that forces its second argument!</p>
|
||
<div class="sourceCode" id="cb89"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb89-1" data-line-number="1"> foldl' (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb89-2" data-line-number="2"><span class="fu">==></span> foldl' (<span class="fu">+</span>) (<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb89-3" data-line-number="3"><span class="co">-- force second argument</span></a>
|
||
<a class="sourceLine" id="cb89-4" data-line-number="4"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb89-5" data-line-number="5"><span class="fu">==></span> foldl' (<span class="fu">+</span>) (<span class="dv">1</span><span class="fu">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb89-6" data-line-number="6"><span class="co">-- force second argument</span></a>
|
||
<a class="sourceLine" id="cb89-7" data-line-number="7"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb89-8" data-line-number="8"><span class="fu">==></span> foldl' (<span class="fu">+</span>) (<span class="dv">3</span><span class="fu">+</span><span class="dv">3</span>) []</a>
|
||
<a class="sourceLine" id="cb89-9" data-line-number="9"><span class="co">-- force second argument</span></a>
|
||
<a class="sourceLine" id="cb89-10" data-line-number="10"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">6</span> []</a>
|
||
<a class="sourceLine" id="cb89-11" data-line-number="11"><span class="fu">==></span> <span class="dv">6</span></a></code></pre></div>
|
||
<p>Now the work is performed incrementally while scanning the list. No space leak! Sometimes too much laziness can cause space leaks, and a bit of strictness can fix them.</p>
|
||
<p>You can find <code>foldl'</code> in the <code>Data.List</code> module, and it works just like this. But how could one implement <code>foldl'</code>? We certainly know by now how to do it for a specific type, say <code>Int</code>. We just add a pattern match on the second argument that doesn’t change the semantics of the function.</p>
|
||
<div class="sourceCode" id="cb90"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb90-1" data-line-number="1"><span class="ot">foldl'Int ::</span> (<span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span>) <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb90-2" data-line-number="2">foldl'Int f z [] <span class="fu">=</span> z</a>
|
||
<a class="sourceLine" id="cb90-3" data-line-number="3">foldl'Int f <span class="dv">0</span> (x<span class="fu">:</span>xs) <span class="fu">=</span> foldl'Int f (f <span class="dv">0</span> x) xs</a>
|
||
<a class="sourceLine" id="cb90-4" data-line-number="4">foldl'Int f z (x<span class="fu">:</span>xs) <span class="fu">=</span> foldl'Int f (f z x) xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb91"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb91-1" data-line-number="1"> foldl'Int (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb91-2" data-line-number="2"><span class="fu">==></span> foldl'Int (<span class="fu">+</span>) (<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb91-3" data-line-number="3"><span class="co">-- to be able to pick between the second and third equations, (0+1) is forced</span></a>
|
||
<a class="sourceLine" id="cb91-4" data-line-number="4"><span class="fu">==></span> foldl'Int (<span class="fu">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb91-5" data-line-number="5"><span class="co">-- the third equation applies</span></a>
|
||
<a class="sourceLine" id="cb91-6" data-line-number="6"><span class="fu">==></span> foldl'Int (<span class="fu">+</span>) (<span class="dv">1</span><span class="fu">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb91-7" data-line-number="7"><span class="co">-- again, we need to pick between the second and third equations</span></a>
|
||
<a class="sourceLine" id="cb91-8" data-line-number="8"><span class="fu">==></span> foldl'Int (<span class="fu">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb91-9" data-line-number="9"><span class="fu">==></span> foldl'Int (<span class="fu">+</span>) (<span class="dv">3</span><span class="fu">+</span><span class="dv">3</span>) []</a>
|
||
<a class="sourceLine" id="cb91-10" data-line-number="10"><span class="fu">==></span> <span class="dv">3</span><span class="fu">+</span><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb91-11" data-line-number="11"><span class="fu">==></span> <span class="dv">6</span></a></code></pre></div>
|
||
<p>To write a generic implementation of <code>foldl'</code> we need to introduce a new built-in function, <code>seq</code>. The call <code>seq a b</code> evaluates to <code>b</code> but forces <code>a</code> into WHNF. Here are some examples of using <code>seq</code> in GHCi. To demonstrate what gets evaluated, we use the special value <code>undefined</code>, which causes an error if something tries to evaluate it into WHNF.</p>
|
||
<div class="sourceCode" id="cb92"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb92-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> seq (not <span class="dt">True</span>) <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb92-2" data-line-number="2"><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb92-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> seq undefined <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb92-4" data-line-number="4"><span class="fu">***</span> <span class="dt">Exception</span><span class="fu">:</span> Prelude.undefined</a>
|
||
<a class="sourceLine" id="cb92-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> (seq (not <span class="dt">True</span>) <span class="dv">3</span>) <span class="fu">+</span> <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb92-6" data-line-number="6"><span class="dv">10</span></a>
|
||
<a class="sourceLine" id="cb92-7" data-line-number="7"><span class="dt">Prelude</span><span class="fu">></span> (seq undefined <span class="dv">3</span>) <span class="fu">+</span> <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb92-8" data-line-number="8"><span class="fu">***</span> <span class="dt">Exception</span><span class="fu">:</span> Prelude.undefined</a>
|
||
<a class="sourceLine" id="cb92-9" data-line-number="9"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">let</span> f x <span class="fu">=</span> f x <span class="kw">in</span> seq (f <span class="dv">3</span>) <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb92-10" data-line-number="10"><span class="co">-- ...infinite recursion</span></a></code></pre></div>
|
||
<p>As an example of using <code>seq</code> in a function, here’s a version of <code>head</code> that doesn’t work for infinite lists (since it evaluates the last element of the list):</p>
|
||
<div class="sourceCode" id="cb93"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb93-1" data-line-number="1"><span class="ot">strictHead ::</span> [a] <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb93-2" data-line-number="2">strictHead xs <span class="fu">=</span> seq (last xs) (head xs)</a></code></pre></div>
|
||
<p>Let’s play around with it in GHCi:</p>
|
||
<div class="sourceCode" id="cb94"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb94-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> head [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb94-2" data-line-number="2"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb94-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> strictHead [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb94-4" data-line-number="4"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb94-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> head (<span class="dv">1</span><span class="fu">:</span><span class="dv">2</span><span class="fu">:</span>undefined)</a>
|
||
<a class="sourceLine" id="cb94-6" data-line-number="6"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb94-7" data-line-number="7"><span class="dt">Prelude</span><span class="fu">></span> strictHead (<span class="dv">1</span><span class="fu">:</span><span class="dv">2</span><span class="fu">:</span>undefined)</a>
|
||
<a class="sourceLine" id="cb94-8" data-line-number="8"><span class="fu">***</span> <span class="dt">Exception</span><span class="fu">:</span> Prelude.undefined</a>
|
||
<a class="sourceLine" id="cb94-9" data-line-number="9"><span class="dt">Prelude</span><span class="fu">></span> head [<span class="dv">1</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb94-10" data-line-number="10"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb94-11" data-line-number="11"><span class="dt">Prelude</span><span class="fu">></span> strictHead [<span class="dv">1</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb94-12" data-line-number="12"><span class="co">-- ...infinite recursion</span></a></code></pre></div>
|
||
<p>Finally, here’s a definition for <code>foldl'</code>. Note how we need to introduce sharing of a new variable, <code>z'</code>, to be able to make <code>seq</code> evaluate the new value and then use it in a recursive call. The new definition is also used in a more detailed evaluation of <code>foldl' (+) 0 [1,2,3]</code> below.</p>
|
||
<div class="sourceCode" id="cb95"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb95-1" data-line-number="1"><span class="ot">foldl' ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> [b] <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb95-2" data-line-number="2">foldl' f z [] <span class="fu">=</span> z</a>
|
||
<a class="sourceLine" id="cb95-3" data-line-number="3">foldl' f z (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">let</span> z' <span class="fu">=</span> f z x</a>
|
||
<a class="sourceLine" id="cb95-4" data-line-number="4"> <span class="kw">in</span> seq z' (foldl f z' xs)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb96"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb96-1" data-line-number="1"> foldl' (<span class="fu">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb96-2" data-line-number="2"><span class="fu">==></span> seq (<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>) (foldl' (<span class="fu">+</span>) (<span class="dv">0</span><span class="fu">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]) <span class="co">-- seq forces first argument</span></a>
|
||
<a class="sourceLine" id="cb96-3" data-line-number="3"> <span class="fu">|</span> <span class="fu">|</span></a>
|
||
<a class="sourceLine" id="cb96-4" data-line-number="4"> <span class="fu">+-----</span>sharing<span class="co">-----'</span></a>
|
||
<a class="sourceLine" id="cb96-5" data-line-number="5"> <span class="fu">|</span> <span class="fu">|</span></a>
|
||
<a class="sourceLine" id="cb96-6" data-line-number="6"><span class="fu">==></span> seq <span class="dv">1</span> (foldl' (<span class="fu">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]) <span class="co">-- first argument to seq in WHNF, seq disappears</span></a>
|
||
<a class="sourceLine" id="cb96-7" data-line-number="7"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb96-8" data-line-number="8"><span class="fu">==></span> seq (<span class="dv">1</span><span class="fu">+</span><span class="dv">2</span>) (foldl' (<span class="fu">+</span>) (<span class="dv">1</span><span class="fu">+</span><span class="dv">2</span>) [<span class="dv">3</span>])</a>
|
||
<a class="sourceLine" id="cb96-9" data-line-number="9"><span class="fu">==></span> seq <span class="dv">3</span> (foldl' (<span class="fu">+</span>) <span class="dv">3</span> [<span class="dv">3</span>])</a>
|
||
<a class="sourceLine" id="cb96-10" data-line-number="10"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb96-11" data-line-number="11"><span class="fu">==></span> seq (<span class="dv">3</span><span class="fu">+</span><span class="dv">3</span>) (foldl' (<span class="fu">+</span>) (<span class="dv">3</span><span class="fu">+</span><span class="dv">3</span>) [])</a>
|
||
<a class="sourceLine" id="cb96-12" data-line-number="12"><span class="fu">==></span> seq <span class="dv">6</span> (foldl' (<span class="fu">+</span>) <span class="dv">6</span> [])</a>
|
||
<a class="sourceLine" id="cb96-13" data-line-number="13"><span class="fu">==></span> foldl' (<span class="fu">+</span>) <span class="dv">6</span> []</a>
|
||
<a class="sourceLine" id="cb96-14" data-line-number="14"><span class="fu">==></span> <span class="dv">6</span></a></code></pre></div>
|
||
<p>We won’t dive deeper into this subject on this course, but it’s important that you’re aware that <code>seq</code> exists. You can find more about <code>seq</code> on <a href="https://wiki.haskell.org/Seq">the Haskell Wiki</a> and learn more about when it is necessary to add strictness in <a href="https://book.realworldhaskell.org/read/profiling-and-optimization.html">Real World Haskell</a>. Often it’s nicer to use <em>bang patterns</em> instead of <code>seq</code>, as discussed by <a href="https://www.fpcomplete.com/blog/2017/09/all-about-strictness/">FPComplete</a> and <a href="http://book.realworldhaskell.org/read/profiling-and-optimization.html">Real World Haskell</a>.</p>
|
||
<h2 id="newtype-declarations"><span class="header-section-number">10.7</span> Newtype Declarations</h2>
|
||
<p>Recall lecture 7. Sometimes we need boxed types. There’s a special keyword <code>newtype</code> that can be used instead of <code>data</code> when a boxed type is needed. <code>newtype</code> expects exactly one constructor, with exactly one field. For instance,</p>
|
||
<div class="sourceCode" id="cb97"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb97-1" data-line-number="1"><span class="kw">newtype</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></a></code></pre></div>
|
||
<p>However, the following won’t work, you need <code>data</code>:</p>
|
||
<div class="sourceCode" id="cb98"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb98-1" data-line-number="1"><span class="co">-- the compiler won't accept these!</span></a>
|
||
<a class="sourceLine" id="cb98-2" data-line-number="2"><span class="kw">newtype</span> <span class="dt">Currency</span> <span class="fu">=</span> <span class="dt">Dollars</span> <span class="dt">Int</span> <span class="fu">|</span> <span class="dt">Euros</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb98-3" data-line-number="3"><span class="kw">newtype</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Money</span> <span class="dt">Int</span> <span class="dt">Int</span></a></code></pre></div>
|
||
<p>So what’s the difference? In terms of writing code, nothing. You work with a <code>newtype</code> exactly as you would with a <code>data</code>. However, the memory layout is different. Using <code>data</code> introduces an indirection layer (the constructor), but using <code>newtype</code> doesn’t. The indirection for <code>data</code> is necessary to support multiple constructors and multiple fields. An illustration:</p>
|
||
<div class="sourceCode" id="cb99"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb99-1" data-line-number="1">code<span class="fu">:</span> memory<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb99-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb99-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Cents</span> <span class="dt">Int</span> x <span class="fu">--></span> <span class="dt">Cents</span> <span class="fu">--></span> <span class="dv">100</span></a>
|
||
<a class="sourceLine" id="cb99-4" data-line-number="4">x <span class="fu">=</span> <span class="dt">Cents</span> <span class="dv">100</span></a>
|
||
<a class="sourceLine" id="cb99-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb99-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb99-7" data-line-number="7"><span class="kw">newtype</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Cents</span> <span class="dt">Int</span> x <span class="fu">--></span> <span class="dv">100</span></a>
|
||
<a class="sourceLine" id="cb99-8" data-line-number="8">x <span class="fu">=</span> <span class="dt">Cents</span> <span class="dv">100</span></a></code></pre></div>
|
||
<p>This difference has many repercussions. First of all, <code>newtype</code> is more efficient: the type can be said to “disappear” when compiling. The type is still checked though, so you get type safety without any performance impact. Secondly, newtypes are <em>strict</em>. Concretely, this means that <code>Money x</code> is in weak head normal form only if <code>x</code> is in WHNF. This can be witnessed in GHCi:</p>
|
||
<div class="sourceCode" id="cb100"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb100-1" data-line-number="1"><span class="co">-- if we use data, Cents undefined is in WHNF</span></a>
|
||
<a class="sourceLine" id="cb100-2" data-line-number="2"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">data</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb100-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> seq (<span class="dt">Cents</span> undefined) <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb100-4" data-line-number="4"><span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb100-5" data-line-number="5"><span class="co">-- if we use newtype, Cents undefined isn't in WHNF, and trying</span></a>
|
||
<a class="sourceLine" id="cb100-6" data-line-number="6"><span class="co">-- to make it so trips up in undefined</span></a>
|
||
<a class="sourceLine" id="cb100-7" data-line-number="7"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">newtype</span> <span class="dt">Money</span> <span class="fu">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb100-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> seq (<span class="dt">Cents</span> undefined) <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb100-9" data-line-number="9"><span class="fu">***</span> <span class="dt">Exception</span><span class="fu">:</span> Prelude.undefined</a></code></pre></div>
|
||
<p>So when should you use <code>newtype</code>? In general it’s best to use <code>newtype</code> whenever you have a single-field single-constructor datatype. However nothing will go catastrophically wrong if you always use <code>data</code>. The <code>newtype</code> pattern is also often used when you need to define a different type class instance for a type. Here’s an example that defines a number type with an inverted ordering</p>
|
||
<div class="sourceCode" id="cb101"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb101-1" data-line-number="1"><span class="kw">newtype</span> <span class="dt">Inverted</span> <span class="fu">=</span> <span class="dt">Inverted</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb101-2" data-line-number="2"> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</a>
|
||
<a class="sourceLine" id="cb101-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb101-4" data-line-number="4"><span class="kw">instance</span> <span class="dt">Ord</span> <span class="dt">Inverted</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb101-5" data-line-number="5"> compare (<span class="dt">Inverted</span> i) (<span class="dt">Inverted</span> j) <span class="fu">=</span> compare j i</a></code></pre></div>
|
||
<div class="sourceCode" id="cb102"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb102-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="fu">></span> sort [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb102-2" data-line-number="2">[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb102-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="fu">></span> sort [<span class="dt">Inverted</span> <span class="dv">1</span>,<span class="dt">Inverted</span> <span class="dv">2</span>,<span class="dt">Inverted</span> <span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb102-4" data-line-number="4">[<span class="dt">Inverted</span> <span class="dv">3</span>,<span class="dt">Inverted</span> <span class="dv">2</span>,<span class="dt">Inverted</span> <span class="dv">1</span>]</a></code></pre></div>
|
||
<h2 id="something-fun-tying-the-knot"><span class="header-section-number">10.8</span> Something Fun: Tying the Knot</h2>
|
||
<!-- TODO: Should we discuss recursion and corecursion? Like
|
||
generating and consuming lists or streams. -->
|
||
<p>Now that we know about sharing and path copying, we can make our own <em>cyclic datastructures</em>. Remember the <code>cycle</code> examples from the list lecture?</p>
|
||
<div class="sourceCode" id="cb103"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb103-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> take <span class="dv">21</span> <span class="fu">$</span> cycle <span class="st">"asdf"</span></a>
|
||
<a class="sourceLine" id="cb103-2" data-line-number="2"><span class="st">"asdfasdfasdfasdfasdfa"</span></a></code></pre></div>
|
||
<p>This is what it looks like in memory:</p>
|
||
<p><img src="img/DAG4.svg" /></p>
|
||
<p>Earlier it was said that Haskell data forms directed graphs in memory. This is an example of a directed graph with a cycle.</p>
|
||
<p>How can we define structures like this? We just give a value a name, and refer to that name in the value itself. That is, the value is <em>recursive</em> or <em>self-referential</em>. This trick is known as <em>tying the knot</em>. A simple example:</p>
|
||
<div class="sourceCode" id="cb104"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb104-1" data-line-number="1"> code memory</a>
|
||
<a class="sourceLine" id="cb104-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb104-3" data-line-number="3"><span class="kw">let</span> xs <span class="fu">=</span> <span class="dv">1</span><span class="fu">:</span><span class="dv">2</span><span class="fu">:</span>xs xs <span class="ot">-></span> (<span class="dv">1</span><span class="fu">:</span>) <span class="ot">-></span> (<span class="dv">2</span><span class="fu">:</span>) <span class="fu">-+</span></a>
|
||
<a class="sourceLine" id="cb104-4" data-line-number="4"> <span class="kw">in</span> xs <span class="fu">^</span> <span class="fu">|</span></a>
|
||
<a class="sourceLine" id="cb104-5" data-line-number="5"> <span class="fu">+------------+</span></a></code></pre></div>
|
||
<p>Note how we use the name <code>xs</code> inside the definition of <code>xs</code>. When we make a recursive definition like this, sharing causes it to turn into a cyclic structure in memory.</p>
|
||
<p>A more fun example: a simple adventure game where the world is a self-referential structure. Note how the cyclic structure is built with local definitions that refer to each other.</p>
|
||
<div class="sourceCode" id="cb105"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb105-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Room</span> <span class="fu">=</span> <span class="dt">Room</span> <span class="dt">String</span> [(<span class="dt">String</span>,<span class="dt">Room</span>)]</a>
|
||
<a class="sourceLine" id="cb105-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb105-3" data-line-number="3"><span class="ot">describe ::</span> <span class="dt">Room</span> <span class="ot">-></span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb105-4" data-line-number="4">describe (<span class="dt">Room</span> s _) <span class="fu">=</span> s</a>
|
||
<a class="sourceLine" id="cb105-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb105-6" data-line-number="6"><span class="ot">move ::</span> <span class="dt">Room</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Room</span></a>
|
||
<a class="sourceLine" id="cb105-7" data-line-number="7">move (<span class="dt">Room</span> _ directions) direction <span class="fu">=</span> lookup direction directions</a>
|
||
<a class="sourceLine" id="cb105-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb105-9" data-line-number="9"><span class="ot">world ::</span> <span class="dt">Room</span></a>
|
||
<a class="sourceLine" id="cb105-10" data-line-number="10">world <span class="fu">=</span> meadow</a>
|
||
<a class="sourceLine" id="cb105-11" data-line-number="11"> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb105-12" data-line-number="12"> meadow <span class="fu">=</span> <span class="dt">Room</span> <span class="st">"It's a flowery meadow next to a cliff."</span> [(<span class="st">"Stay"</span>,meadow),(<span class="st">"Enter cave"</span>,cave)]</a>
|
||
<a class="sourceLine" id="cb105-13" data-line-number="13"> cave <span class="fu">=</span> <span class="dt">Room</span> <span class="st">"You are in a cave"</span> [(<span class="st">"Exit"</span>,meadow),(<span class="st">"Go deeper"</span>,tunnel)]</a>
|
||
<a class="sourceLine" id="cb105-14" data-line-number="14"> tunnel <span class="fu">=</span> <span class="dt">Room</span> <span class="st">"This is a very dark tunnel. It seems you can either go left or right."</span></a>
|
||
<a class="sourceLine" id="cb105-15" data-line-number="15"> [(<span class="st">"Go back"</span>,cave),(<span class="st">"Go left"</span>,pit),(<span class="st">"Go right"</span>,treasure)]</a>
|
||
<a class="sourceLine" id="cb105-16" data-line-number="16"> pit <span class="fu">=</span> <span class="dt">Room</span> <span class="st">"You fall into a pit. There is no way out."</span> []</a>
|
||
<a class="sourceLine" id="cb105-17" data-line-number="17"> treasure <span class="fu">=</span> <span class="dt">Room</span> <span class="st">"A green light from a terminal fills the room. The terminal says <<loop>>."</span></a>
|
||
<a class="sourceLine" id="cb105-18" data-line-number="18"> [(<span class="st">"Go back"</span>,tunnel)]</a>
|
||
<a class="sourceLine" id="cb105-19" data-line-number="19"></a>
|
||
<a class="sourceLine" id="cb105-20" data-line-number="20"><span class="ot">play ::</span> <span class="dt">Room</span> <span class="ot">-></span> [<span class="dt">String</span>] <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb105-21" data-line-number="21">play room [] <span class="fu">=</span> [describe room]</a>
|
||
<a class="sourceLine" id="cb105-22" data-line-number="22">play room (d<span class="fu">:</span>ds) <span class="fu">=</span> <span class="kw">case</span> move room d <span class="kw">of</span> <span class="dt">Nothing</span> <span class="ot">-></span> [describe room]</a>
|
||
<a class="sourceLine" id="cb105-23" data-line-number="23"> <span class="dt">Just</span> r <span class="ot">-></span> describe room <span class="fu">:</span> play r ds</a></code></pre></div>
|
||
<div class="sourceCode" id="cb106"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb106-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> play world [<span class="st">"Stay"</span>,<span class="st">"Enter cave"</span>,<span class="st">"Go deeper"</span>,<span class="st">"Go back"</span>,<span class="st">"Go deeper"</span>,<span class="st">"Go right"</span>]</a>
|
||
<a class="sourceLine" id="cb106-2" data-line-number="2">[<span class="st">"It's a flowery meadow next to a cliff."</span>,</a>
|
||
<a class="sourceLine" id="cb106-3" data-line-number="3"> <span class="st">"It's a flowery meadow next to a cliff."</span>,</a>
|
||
<a class="sourceLine" id="cb106-4" data-line-number="4"> <span class="st">"You are in a cave"</span>,</a>
|
||
<a class="sourceLine" id="cb106-5" data-line-number="5"> <span class="st">"This is a very dark tunnel. It seems you can either go left or right."</span>,</a>
|
||
<a class="sourceLine" id="cb106-6" data-line-number="6"> <span class="st">"You are in a cave"</span>,</a>
|
||
<a class="sourceLine" id="cb106-7" data-line-number="7"> <span class="st">"This is a very dark tunnel. It seems you can either go left or right."</span>,</a>
|
||
<a class="sourceLine" id="cb106-8" data-line-number="8"> <span class="st">"A green light from a computer terminal floods the room. The terminal says <<loop>>."</span>]</a></code></pre></div>
|
||
<p>Here’s what the <code>world</code> of the game looks like in memory:</p>
|
||
<pre><code> ,-----------------,
|
||
v |
|
||
+-----------------------|-----------------+
|
||
meadow-->|Room "It's..." ["Stay" o, "Enter cave" o]|
|
||
+---------------------------------------|-+
|
||
^ v
|
||
+--------------------------|----------------+
|
||
cave---->|Room "You are..." ["Exit" o, "Go deeper" o]|
|
||
+-----------------------------------------|-+
|
||
^ v
|
||
+-----------------------------|----------------------------+
|
||
tunnel-->|Room "This is..." ["Go back" o, "Go left" o, "Go right" o]|<--------,
|
||
+------------------------------------------|-------------|-+ |
|
||
| | |
|
||
,------------------------------' | |
|
||
v v |
|
||
+---------------------+ +-----------------------------|-+
|
||
pit----->|Room "You fall..." []| treasure--->|Room "A green..." ["Go back" o]|
|
||
+---------------------+ +-------------------------------+</code></pre>
|
||
<p>We’ve now seen three types of recursion. Recursive functions call themselves. Recursive types allow us to express arbitarily large structures. Recursive values are one way to implement infinite structures.</p>
|
||
<h2 id="something-fun-debug.trace"><span class="header-section-number">10.9</span> Something Fun: Debug.Trace</h2>
|
||
<p>Even though Haskell is a pure programming language, we can sometimes gain insights by sprinkling in a bit of impurity.</p>
|
||
<p>We can use the function <code>trace :: String -> a -> a</code> from the module <code>Debug.Trace</code> to peek into Haskell evaluation. The expression <code>trace "message" x</code> is the same as <code>x</code>, but prints <code>message</code> when it is evaluated (forced). We can use <code>trace</code> to witness the laziness of the <code>||</code> operator:</p>
|
||
<div class="sourceCode" id="cb108"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb108-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">import</span> <span class="dt">Debug.Trace</span></a>
|
||
<a class="sourceLine" id="cb108-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> trace <span class="st">"a"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb108-3" data-line-number="3">a</a>
|
||
<a class="sourceLine" id="cb108-4" data-line-number="4"><span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb108-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> trace <span class="st">"a"</span> <span class="dt">False</span> <span class="fu">||</span> trace <span class="st">"b"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb108-6" data-line-number="6">a</a>
|
||
<a class="sourceLine" id="cb108-7" data-line-number="7">b</a>
|
||
<a class="sourceLine" id="cb108-8" data-line-number="8"><span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb108-9" data-line-number="9"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> trace <span class="st">"a"</span> <span class="dt">True</span> <span class="fu">||</span> trace <span class="st">"b"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb108-10" data-line-number="10">a</a>
|
||
<a class="sourceLine" id="cb108-11" data-line-number="11"><span class="dt">True</span></a></code></pre></div>
|
||
<p>We can also have a look at when list elements are evaluated. Note how <code>length</code> doesn’t need to evaluate the elements of the list, and <code>sum</code> needs to evaluate all of them. (To be precise, <code>head xs</code> doesn’t actually evaluate the first element of <code>xs</code>, but returns it to GHCi, which evaluates it in order to show it.)</p>
|
||
<div class="sourceCode" id="cb109"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb109-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> head [trace <span class="st">"first"</span> <span class="dv">1</span>, trace <span class="st">"second"</span> <span class="dv">2</span>, trace <span class="st">"third"</span> <span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb109-2" data-line-number="2">first</a>
|
||
<a class="sourceLine" id="cb109-3" data-line-number="3"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb109-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> last [trace <span class="st">"first"</span> <span class="dv">1</span>, trace <span class="st">"second"</span> <span class="dv">2</span>, trace <span class="st">"third"</span> <span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb109-5" data-line-number="5">third</a>
|
||
<a class="sourceLine" id="cb109-6" data-line-number="6"><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb109-7" data-line-number="7"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> length [trace <span class="st">"first"</span> <span class="dv">1</span>, trace <span class="st">"second"</span> <span class="dv">2</span>, trace <span class="st">"third"</span> <span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb109-8" data-line-number="8"><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb109-9" data-line-number="9"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> sum [trace <span class="st">"first"</span> <span class="dv">1</span>, trace <span class="st">"second"</span> <span class="dv">2</span>, trace <span class="st">"third"</span> <span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb109-10" data-line-number="10">third</a>
|
||
<a class="sourceLine" id="cb109-11" data-line-number="11">second</a>
|
||
<a class="sourceLine" id="cb109-12" data-line-number="12">first</a>
|
||
<a class="sourceLine" id="cb109-13" data-line-number="13"><span class="dv">6</span></a></code></pre></div>
|
||
<p><code>Debug.Trace</code> also offers useful variants of <code>trace</code>. A notable one is <code>traceShowId x</code> which prints <code>show x</code> and evaluates to <code>x</code>. Let’s verify the evaluation of our previous head-filter-map example using <code>traceShowId</code>. Note how even though we map <code>traceShowId</code> over the infinite list <code>[0..]</code>, only 6 values are actually evaluated. The last 243 is the returned value, not a trace print.</p>
|
||
<div class="sourceCode" id="cb110"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb110-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> head (filter (<span class="fu">></span><span class="dv">100</span>) (map (\x <span class="ot">-></span> traceShowId (<span class="dv">3</span><span class="fu">^</span>x)) [<span class="dv">0</span><span class="fu">..</span>]))</a>
|
||
<a class="sourceLine" id="cb110-2" data-line-number="2"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb110-3" data-line-number="3"><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb110-4" data-line-number="4"><span class="dv">9</span></a>
|
||
<a class="sourceLine" id="cb110-5" data-line-number="5"><span class="dv">27</span></a>
|
||
<a class="sourceLine" id="cb110-6" data-line-number="6"><span class="dv">81</span></a>
|
||
<a class="sourceLine" id="cb110-7" data-line-number="7"><span class="dv">243</span></a>
|
||
<a class="sourceLine" id="cb110-8" data-line-number="8"><span class="dv">243</span></a></code></pre></div>
|
||
<p><code>Debug.Trace</code> is especially useful when you have an infinite recursion bug. Here’s an example:</p>
|
||
<div class="sourceCode" id="cb111"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb111-1" data-line-number="1"><span class="co">-- computes sums like 7+5+3+1</span></a>
|
||
<a class="sourceLine" id="cb111-2" data-line-number="2"><span class="ot">sumEverySecond ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb111-3" data-line-number="3">sumEverySecond <span class="dv">0</span> <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb111-4" data-line-number="4">sumEverySecond n <span class="fu">=</span> n <span class="fu">+</span> sumEverySecond (n<span class="fu">-</span><span class="dv">2</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb112"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb112-1" data-line-number="1">sumEverySecond <span class="dv">6</span> <span class="fu">==></span> <span class="dv">12</span></a>
|
||
<a class="sourceLine" id="cb112-2" data-line-number="2">sumEverySecond <span class="dv">7</span> <span class="fu">==></span> doesn't terminate</a></code></pre></div>
|
||
<p>We can debug this by adding a <code>trace</code> to wrap the whole recursive case.</p>
|
||
<div class="sourceCode" id="cb113"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb113-1" data-line-number="1"><span class="ot">sumEverySecond ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb113-2" data-line-number="2">sumEverySecond <span class="dv">0</span> <span class="fu">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb113-3" data-line-number="3">sumEverySecond n <span class="fu">=</span> trace (<span class="st">"sumEverySecond "</span><span class="fu">++</span>show n) (n <span class="fu">+</span> sumEverySecond (n<span class="fu">-</span><span class="dv">2</span>))</a></code></pre></div>
|
||
<div class="sourceCode" id="cb114"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb114-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> sumEverySecond <span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb114-2" data-line-number="2">sumEverySecond <span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb114-3" data-line-number="3">sumEverySecond <span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb114-4" data-line-number="4">sumEverySecond <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb114-5" data-line-number="5"><span class="dv">12</span></a>
|
||
<a class="sourceLine" id="cb114-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> sumEverySecond <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb114-7" data-line-number="7">sumEverySecond <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb114-8" data-line-number="8">sumEverySecond <span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb114-9" data-line-number="9">sumEverySecond <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb114-10" data-line-number="10">sumEverySecond <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb114-11" data-line-number="11">sumEverySecond <span class="fu">-</span><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb114-12" data-line-number="12">sumEverySecond <span class="fu">-</span><span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb114-13" data-line-number="13">sumEverySecond <span class="fu">-</span><span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb114-14" data-line-number="14"><span class="co">-- and so on</span></a></code></pre></div>
|
||
<p>A ha! The problem is that our recursion base case of <code>sumEverySecond 0</code> is not enough to stop the recursion.</p>
|
||
<p>Finally, a word of caution. Using <code>trace</code>, and especially <code>traceShowId</code>, can cause things that would not otherwise get evaluated to get evaluated. For example:</p>
|
||
<div class="sourceCode" id="cb115"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb115-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> <span class="kw">let</span> traceHead xs <span class="fu">=</span> head (traceShowId xs)</a>
|
||
<a class="sourceLine" id="cb115-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="fu">></span> traceHead [<span class="dv">0</span><span class="fu">..</span>]</a>
|
||
<a class="sourceLine" id="cb115-3" data-line-number="3"><span class="co">-- never terminates since it's trying to show an infinite list</span></a></code></pre></div>
|
||
<p>So feel free to use <code>Debug.Trace</code> when working on the exercises, but try to leave <code>trace</code> calls out of your final answers. Some exercise sets check your imports and disallow <code>Debug.Trace</code>.</p>
|
||
<p>We’ll see a more principled way of dealing with side effects in the next lecture!</p>
|
||
<h2 id="quiz-1"><span class="header-section-number">10.10</span> Quiz</h2>
|
||
<p>Which of these statements is true?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>reverse . reverse . reverse === reverse</code>
|
||
</li>
|
||
<li>
|
||
<code>reverse . reverse === reverse</code>
|
||
</li>
|
||
<li>
|
||
<code>reverse . id === id</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these is an infinite list that starts with <code>[0,1,2,1,2,1,2...]</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>cycle [0,1,2]</code>
|
||
</li>
|
||
<li>
|
||
<code>0:repeat [1,2]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>0:cycle [1,2]</code>
|
||
</li>
|
||
<li>
|
||
<code>0:[1,2..]</code>
|
||
</li>
|
||
</ol>
|
||
<p>What’s the next step when evaluating this expression?</p>
|
||
<div class="sourceCode" id="cb116"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb116-1" data-line-number="1">head (map not (<span class="dt">True</span><span class="fu">:</span><span class="dt">False</span><span class="fu">:</span>[]))</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>head (False : True : [])</code>
|
||
</li>
|
||
<li>
|
||
<code>head (not True)</code>
|
||
</li>
|
||
<li>
|
||
<code>head (False : map not (False:[]))</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>head (not True : map not (False:[]))</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these values is <em>not</em> in weak head normal form?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>map</code>
|
||
</li>
|
||
<li>
|
||
<code>f 1 : map f (2 : [])</code>
|
||
</li>
|
||
<li>
|
||
<code>Just (not False)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(\x -> x) True</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these statements about the following function is true?</p>
|
||
<div class="sourceCode" id="cb117"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb117-1" data-line-number="1">f <span class="dv">0</span> x <span class="fu">=</span> <span class="dv">1</span><span class="fu">+</span>x</a>
|
||
<a class="sourceLine" id="cb117-2" data-line-number="2">f _ x <span class="fu">=</span> <span class="dv">2</span><span class="fu">+</span>x</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>f</code> is strict in its left argument
|
||
</li>
|
||
<li>
|
||
<code>f</code> is strict in its right argument
|
||
</li>
|
||
<li class="correct">
|
||
<code>f</code> forces both of its arguments
|
||
</li>
|
||
<li>
|
||
None of the above
|
||
</li>
|
||
</ol>
|
||
<p>Does this function work with infinite lists as input? Why?</p>
|
||
<div class="sourceCode" id="cb118"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb118-1" data-line-number="1">f [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb118-2" data-line-number="2">f (x<span class="fu">:</span>xs) <span class="fu">=</span> x <span class="fu">:</span> map not xs</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
No, because it includes a <code>[]</code> case, which is never reached.
|
||
</li>
|
||
<li>
|
||
No, because it uses <code>map</code>, which evaluates the whole list.
|
||
</li>
|
||
<li class="correct">
|
||
Yes, because it only looks at the first element of the list before producing a WHNF value.
|
||
</li>
|
||
<li>
|
||
Yes, because it calls <code>map</code>, which works with infinite lists.
|
||
</li>
|
||
</ol>
|
||
<p>What about this one?</p>
|
||
<div class="sourceCode" id="cb119"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb119-1" data-line-number="1">f xs <span class="fu">=</span> map (<span class="fu">+</span>(sum xs)) xs</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
No, because it uses <code>map</code>, which evaluates the whole list.
|
||
</li>
|
||
<li class="correct">
|
||
No, because computing the <code>head</code> of the result needs the whole input list.
|
||
</li>
|
||
<li>
|
||
Yes, because it doesn’t includes a <code>[]</code> case
|
||
</li>
|
||
<li>
|
||
Yes, because it calls <code>map</code>, which works with infinite lists.
|
||
</li>
|
||
</ol>
|
||
<h2 id="exercises-1"><span class="header-section-number">10.11</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set10a.hs">Set10a</a></li>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set10b.hs">Set10b</a></li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
<h1 id="lecture-11-realworld---arealworld"><span class="header-section-number">11</span> Lecture 11: <code>RealWorld -> (a,RealWorld)</code></h1>
|
||
<h2 id="contents"><span class="header-section-number">11.1</span> Contents</h2>
|
||
<ul>
|
||
<li>IO</li>
|
||
</ul>
|
||
<h2 id="youve-been-fooled"><span class="header-section-number">11.2</span> You’ve Been Fooled!</h2>
|
||
<p>Forget what we talked about functional programming and purity. Actually, Haskell is the <em>world’s best imperative programming language</em>! Let’s start:</p>
|
||
<div class="sourceCode" id="cb120"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb120-1" data-line-number="1">questionnaire <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb120-2" data-line-number="2"> putStrLn <span class="st">"Write something!"</span></a>
|
||
<a class="sourceLine" id="cb120-3" data-line-number="3"> s <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb120-4" data-line-number="4"> putStrLn (<span class="st">"You wrote: "</span><span class="fu">++</span>s)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb121"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb121-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> questionnaire</a>
|
||
<a class="sourceLine" id="cb121-2" data-line-number="2"><span class="dt">Write</span> something<span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb121-3" data-line-number="3"><span class="dt">Haskell</span><span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb121-4" data-line-number="4"><span class="dt">You</span> wrote<span class="fu">:</span> <span class="dt">Haskell</span><span class="fu">!</span></a></code></pre></div>
|
||
<p>Reading input and writing output was easy enough. We can also read stuff over the network. Here’s a complete Haskell program that fetches a some words from a URL using HTTP and prints them.</p>
|
||
<div class="sourceCode" id="cb122"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb122-1" data-line-number="1"><span class="kw">import</span> <span class="dt">Network.HTTP</span></a>
|
||
<a class="sourceLine" id="cb122-2" data-line-number="2"><span class="kw">import</span> <span class="dt">Control.Monad</span></a>
|
||
<a class="sourceLine" id="cb122-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb122-4" data-line-number="4">main <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb122-5" data-line-number="5"> rsp <span class="ot"><-</span> simpleHTTP (getRequest <span class="st">"http://httpbin.org/base64/aGFza2VsbCBmb3IgZXZlcgo="</span>)</a>
|
||
<a class="sourceLine" id="cb122-6" data-line-number="6"> body <span class="ot"><-</span> getResponseBody rsp</a>
|
||
<a class="sourceLine" id="cb122-7" data-line-number="7"> forM_ (words body) <span class="fu">$</span> \w <span class="ot">-></span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb122-8" data-line-number="8"> putStr <span class="st">"word: "</span></a>
|
||
<a class="sourceLine" id="cb122-9" data-line-number="9"> putStrLn w</a></code></pre></div>
|
||
<p>You can find this program in the course repository as <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/FetchWords.hs"><code>exercises/Examples/FetchWords.hs</code></a>, and you can run it like this:</p>
|
||
<pre><code>$ cd exercises/Examples
|
||
$ stack runhaskell FetchWords.hs
|
||
word: haskell
|
||
word: for
|
||
word: ever</code></pre>
|
||
<p>What’s going on here? Let’s look at the types:</p>
|
||
<div class="sourceCode" id="cb124"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb124-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t putStrLn</a>
|
||
<a class="sourceLine" id="cb124-2" data-line-number="2">putStrLn<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb124-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t getLine</a>
|
||
<a class="sourceLine" id="cb124-4" data-line-number="4">getLine<span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></a></code></pre></div>
|
||
<p>A value of type <code>IO a</code> is an <em>operation</em> that <em>produces</em> a value of type <code>a</code>. So <code>getLine</code> is an IO operation that produces a string. The <code>()</code> type is the so called <em>unit type</em>, its only value is <code>()</code>. It’s mostly used when an IO operation doesn’t return anything (but rather just has side effects).</p>
|
||
<p>A comparison with Java (method) types might help:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Haskell type</th>
|
||
<th style="text-align: left;">Java type</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>doIt :: IO ()</code></td>
|
||
<td style="text-align: left;"><code>void doIt()</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>getSomething :: IO Int</code></td>
|
||
<td style="text-align: left;"><code>int getSomething()</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>force :: a -> b -> IO ()</code></td>
|
||
<td style="text-align: left;"><code>void force(a arg0, b arg1)</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>mogrify :: c -> IO d</code></td>
|
||
<td style="text-align: left;"><code>d mogrify(c arg)</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>IO operations can be combined into bigger operations using <em>do-notation</em>.</p>
|
||
<div class="sourceCode" id="cb125"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb125-1" data-line-number="1"><span class="kw">do</span> operation</a>
|
||
<a class="sourceLine" id="cb125-2" data-line-number="2"> operation arg</a>
|
||
<a class="sourceLine" id="cb125-3" data-line-number="3"> variable <span class="ot"><-</span> operationThatReturnsStuff</a>
|
||
<a class="sourceLine" id="cb125-4" data-line-number="4"> <span class="kw">let</span> var2 <span class="fu">=</span> expression</a>
|
||
<a class="sourceLine" id="cb125-5" data-line-number="5"> operationThatProducesTheResult var2</a></code></pre></div>
|
||
<h3 id="examples"><span class="header-section-number">11.2.1</span> Examples</h3>
|
||
<p>You can find useful IO operations in the standard library modules <a href="https://hackage.haskell.org/package/base-4.13.0.0/docs/Prelude.html">Prelude</a> and <a href="https://hackage.haskell.org/package/base-4.13.0.0/docs/System-IO.html">System.IO</a></p>
|
||
<p>Here’s an IO operation that asks the user for a string, and prints out the length of the string.</p>
|
||
<div class="sourceCode" id="cb126"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb126-1" data-line-number="1"><span class="ot">query ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb126-2" data-line-number="2">query <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb126-3" data-line-number="3"> putStrLn <span class="st">"Write something!"</span> <span class="co">-- run an operation, ignore produced value</span></a>
|
||
<a class="sourceLine" id="cb126-4" data-line-number="4"> s <span class="ot"><-</span> getLine <span class="co">-- run an operation, capture produced value</span></a>
|
||
<a class="sourceLine" id="cb126-5" data-line-number="5"> <span class="kw">let</span> n <span class="fu">=</span> length s <span class="co">-- run a pure function</span></a>
|
||
<a class="sourceLine" id="cb126-6" data-line-number="6"> putStrLn (<span class="st">"You wrote "</span><span class="fu">++</span>show n<span class="fu">++</span><span class="st">" characters"</span>) <span class="co">-- run an operation, passing on the produced value</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb127"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb127-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> query</a>
|
||
<a class="sourceLine" id="cb127-2" data-line-number="2"><span class="dt">Write</span> something<span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb127-3" data-line-number="3">lorem ipsum</a>
|
||
<a class="sourceLine" id="cb127-4" data-line-number="4"><span class="dt">You</span> wrote <span class="dv">11</span> characters</a></code></pre></div>
|
||
<p>The value produced by the last line of a <code>do</code> block is the value produced by the whole block. Note how <code>askForALine</code> has the same type as <code>getLine</code>, <code>IO String</code>:</p>
|
||
<div class="sourceCode" id="cb128"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb128-1" data-line-number="1"><span class="ot">askForALine ::</span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb128-2" data-line-number="2">askForALine <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb128-3" data-line-number="3"> putStrLn <span class="st">"Please give me a line"</span></a>
|
||
<a class="sourceLine" id="cb128-4" data-line-number="4"> getLine</a></code></pre></div>
|
||
<p>In addition to IO operations like <code>query</code> you can also run IO operations that produce values, like <code>askForALine</code>, in GHCi. You can use <code><-</code> to capture the result of the operation into a variable if you want.</p>
|
||
<div class="sourceCode" id="cb129"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb129-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> askForALine</a>
|
||
<a class="sourceLine" id="cb129-2" data-line-number="2"><span class="dt">Please</span> give me a line</a>
|
||
<a class="sourceLine" id="cb129-3" data-line-number="3">this is a line</a>
|
||
<a class="sourceLine" id="cb129-4" data-line-number="4"><span class="st">"this is a line"</span></a>
|
||
<a class="sourceLine" id="cb129-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> line <span class="ot"><-</span> askForALine</a>
|
||
<a class="sourceLine" id="cb129-6" data-line-number="6"><span class="dt">Please</span> give me a line</a>
|
||
<a class="sourceLine" id="cb129-7" data-line-number="7">this is a line</a>
|
||
<a class="sourceLine" id="cb129-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t line</a>
|
||
<a class="sourceLine" id="cb129-9" data-line-number="9"><span class="ot">line ::</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb129-10" data-line-number="10"><span class="dt">Prelude</span><span class="fu">></span> line</a>
|
||
<a class="sourceLine" id="cb129-11" data-line-number="11"><span class="st">"this is a line"</span></a></code></pre></div>
|
||
<p>If you need to give your operation parameters, you can just make <em>a function that returns an operation</em>. Note how <code>ask</code> has a function type with a <code>-></code>, just like a normal function. We also use normal function definition syntax to give the parameter the name <code>question</code>.</p>
|
||
<div class="sourceCode" id="cb130"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb130-1" data-line-number="1"><span class="ot">ask ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb130-2" data-line-number="2">ask question <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb130-3" data-line-number="3"> putStrLn question</a>
|
||
<a class="sourceLine" id="cb130-4" data-line-number="4"> getLine</a></code></pre></div>
|
||
<div class="sourceCode" id="cb131"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb131-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> ask <span class="st">"What is love?"</span></a>
|
||
<a class="sourceLine" id="cb131-2" data-line-number="2"><span class="dt">What</span> is love<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb131-3" data-line-number="3"><span class="dt">Baby</span> don't hurt me<span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb131-4" data-line-number="4"><span class="st">"Baby don't hurt me!"</span></a>
|
||
<a class="sourceLine" id="cb131-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> response <span class="ot"><-</span> ask <span class="st">"Who are you?"</span></a>
|
||
<a class="sourceLine" id="cb131-6" data-line-number="6"><span class="dt">Who</span> are you<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb131-7" data-line-number="7"><span class="dt">The</span> programmer<span class="fu">.</span></a>
|
||
<a class="sourceLine" id="cb131-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> response</a>
|
||
<a class="sourceLine" id="cb131-9" data-line-number="9"><span class="st">"The programmer."</span></a>
|
||
<a class="sourceLine" id="cb131-10" data-line-number="10"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t response</a>
|
||
<a class="sourceLine" id="cb131-11" data-line-number="11"><span class="ot">response ::</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb131-12" data-line-number="12"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t ask</a>
|
||
<a class="sourceLine" id="cb131-13" data-line-number="13"><span class="ot">ask ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb131-14" data-line-number="14"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t ask <span class="st">"Who are you?"</span></a>
|
||
<a class="sourceLine" id="cb131-15" data-line-number="15">ask <span class="st">"Who are you?"</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></a></code></pre></div>
|
||
<h2 id="the-subtle-return"><span class="header-section-number">11.3</span> The Subtle <code>return</code></h2>
|
||
<p>The Haskell function <code>return</code> is named a bit misleadingly. In other languages <code>return</code> is a built-in keyword, but in Haskell it’s just a function. The <code>return :: a -> IO a</code> function takes a value and turns it into an <em>operation, that produces the value</em>.</p>
|
||
<div class="sourceCode" id="cb132"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb132-1" data-line-number="1"><span class="ot">produceThree ::</span> <span class="dt">IO</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb132-2" data-line-number="2">produceThree <span class="fu">=</span> return <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb132-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb132-4" data-line-number="4"><span class="ot">printThree ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb132-5" data-line-number="5">printThree <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb132-6" data-line-number="6"> three <span class="ot"><-</span> produceThree</a>
|
||
<a class="sourceLine" id="cb132-7" data-line-number="7"> putStrLn (show three)</a></code></pre></div>
|
||
<p>That doesn’t sound very useful does it? Combined with do-notation it is. Here we return a boolean according to whether the user answered <code>Y</code> or <code>N</code>:</p>
|
||
<div class="sourceCode" id="cb133"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb133-1" data-line-number="1"><span class="ot">yesNoQuestion ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb133-2" data-line-number="2">yesNoQuestion question <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb133-3" data-line-number="3"> putStrLn question</a>
|
||
<a class="sourceLine" id="cb133-4" data-line-number="4"> s <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb133-5" data-line-number="5"> return (s <span class="fu">==</span> <span class="st">"Y"</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb134"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb134-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> yesNoQuestion <span class="st">"Fire the missiles?"</span></a>
|
||
<a class="sourceLine" id="cb134-2" data-line-number="2"><span class="dt">Fire</span> the missiles<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb134-3" data-line-number="3"><span class="dt">Y</span></a>
|
||
<a class="sourceLine" id="cb134-4" data-line-number="4"><span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb134-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> answer <span class="ot"><-</span> yesNoQuestion <span class="st">"Are you sure?"</span></a>
|
||
<a class="sourceLine" id="cb134-6" data-line-number="6"><span class="dt">Are</span> you sure<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb134-7" data-line-number="7"><span class="dt">N</span></a>
|
||
<a class="sourceLine" id="cb134-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>t answer</a>
|
||
<a class="sourceLine" id="cb134-9" data-line-number="9"><span class="ot">answer ::</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb134-10" data-line-number="10"><span class="dt">Prelude</span><span class="fu">></span> answer</a>
|
||
<a class="sourceLine" id="cb134-11" data-line-number="11"><span class="dt">False</span></a></code></pre></div>
|
||
<p><strong>Note!</strong> This means that return <em>does not stop execution</em> of an operation (unlike return in Java or C). Remember that in do-blocks, the last line decides which value to produce. This means that this operation produces <code>2</code>:</p>
|
||
<div class="sourceCode" id="cb135"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb135-1" data-line-number="1"><span class="ot">produceTwo ::</span> <span class="dt">IO</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb135-2" data-line-number="2">produceTwo <span class="fu">=</span> <span class="kw">do</span> return <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb135-3" data-line-number="3"> return <span class="dv">2</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb136"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb136-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> produceTwo</a>
|
||
<a class="sourceLine" id="cb136-2" data-line-number="2"><span class="dv">2</span></a></code></pre></div>
|
||
<p>Let’s look at this another way. The <code>do</code> notation allows us to cause a sequence of side-effects, and finally to produce a value.</p>
|
||
<pre><code>produceThree = do putStrLn "1" -- side effect, produces (), which is ignored
|
||
return 2 -- no side effect, produces 2, which is ignored
|
||
getLine -- side effect, produces a String, which is ignored
|
||
return 3 -- no side effect, produces 3, which is passed on</code></pre>
|
||
<pre><code>Prelude> final <- produceThree
|
||
1
|
||
this line is ignored
|
||
Prelude> final
|
||
3</code></pre>
|
||
<p>Also note that these are the same operation:</p>
|
||
<div class="sourceCode" id="cb139"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb139-1" data-line-number="1"><span class="kw">do</span> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb139-2" data-line-number="2"> x <span class="ot"><-</span> op</a>
|
||
<a class="sourceLine" id="cb139-3" data-line-number="3"> return x</a></code></pre></div>
|
||
<div class="sourceCode" id="cb140"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb140-1" data-line-number="1"><span class="kw">do</span> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb140-2" data-line-number="2"> op</a></code></pre></div>
|
||
<p>Since <code>return</code> is a function, you should remember to parenthesize any complex expressions:</p>
|
||
<div class="sourceCode" id="cb141"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb141-1" data-line-number="1">return (f x <span class="fu">:</span> xs)</a>
|
||
<a class="sourceLine" id="cb141-2" data-line-number="2"><span class="co">-- alternatively:</span></a>
|
||
<a class="sourceLine" id="cb141-3" data-line-number="3">return <span class="fu">$</span> f x <span class="fu">:</span> xs</a></code></pre></div>
|
||
<h2 id="do-and-types"><span class="header-section-number">11.4</span> <code>do</code> and Types</h2>
|
||
<p>Let’s look at the typing of do-notation in more detail. A do-block builds a value of type <code>IO <something></code>. For example in</p>
|
||
<div class="sourceCode" id="cb142"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb142-1" data-line-number="1">foo <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb142-2" data-line-number="2"> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb142-3" data-line-number="3"> lastOp</a></code></pre></div>
|
||
<p>The <code>lastOp</code> must be of type <code>IO X</code> (for some <code>X</code>). The type of <code>foo</code> will also be <code>IO X</code>. Let’s look at an example with parameters next:</p>
|
||
<div class="sourceCode" id="cb143"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb143-1" data-line-number="1">bar x y <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb143-2" data-line-number="2"> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb143-3" data-line-number="3"> lastOp arg</a></code></pre></div>
|
||
<p>The <code>lastOp</code> must be of type <code>Y -> IO X</code> (so that <code>lastOp arg</code> has type <code>IO X</code>). The type of <code>bar</code> will be <code>A -> B -> IO X</code> (and inside <code>bar</code> we’ll have <code>x :: A</code> and <code>y :: B</code>).</p>
|
||
<p>If we use <code>return</code>:</p>
|
||
<div class="sourceCode" id="cb144"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb144-1" data-line-number="1">quux x <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb144-2" data-line-number="2"> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb144-3" data-line-number="3"> return value</a></code></pre></div>
|
||
<p>The function <code>quux</code> will have type <code>A -> IO B</code>, where <code>x :: A</code> and <code>value :: B</code>.</p>
|
||
<p>Let’s look at the typing of <code><-</code> next. If <code>op :: IO X</code> and you have <code>var <- op</code>, <code>var</code> will have type <code>X</code>. We’ve seen this in many GHCi examples.</p>
|
||
<p>The last line of a <code>do</code> cannot be <code>foo <- bar</code>. The last line determines what the whole operation produces, so it must be an operation (for example, <code>return something</code>).</p>
|
||
<p>Here’s a worked example:</p>
|
||
<div class="sourceCode" id="cb145"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb145-1" data-line-number="1"><span class="ot">alwaysFine ::</span> <span class="dt">IO</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb145-2" data-line-number="2">alwaysFine <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb145-3" data-line-number="3"> putStrLn <span class="st">"What?"</span> <span class="co">-- :: IO ()</span></a>
|
||
<a class="sourceLine" id="cb145-4" data-line-number="4"> return <span class="dv">2</span> <span class="co">-- :: IO Int, produced value is discarded</span></a>
|
||
<a class="sourceLine" id="cb145-5" data-line-number="5"> s <span class="ot"><-</span> getLine <span class="co">-- getLine :: IO String, thus s :: String</span></a>
|
||
<a class="sourceLine" id="cb145-6" data-line-number="6"> putStrLn s <span class="co">-- putStrLn :: String -> IO (), thus putStrLn s :: IO ()</span></a>
|
||
<a class="sourceLine" id="cb145-7" data-line-number="7"> <span class="kw">let</span> b <span class="fu">=</span> <span class="dt">True</span> <span class="co">-- b :: Bool</span></a>
|
||
<a class="sourceLine" id="cb145-8" data-line-number="8"> return b <span class="co">-- :: IO Bool</span></a>
|
||
<a class="sourceLine" id="cb145-9" data-line-number="9"> <span class="co">-- Thus, alwaysFine :: IO Bool</span></a></code></pre></div>
|
||
<p>The typing rules guarantee that you can not “escape” <code>IO</code>. Even though <code><-</code> gives you an <code>X</code> from an <code>IO X</code>, you can only use <code><-</code> inside <code>do</code>. However a <code>do</code> always means a value of type <code>IO Y</code>. In other words: you can temporarily open the <code>IO</code> box, but you must return into it. <em>“What happens in IO, stays in IO.”</em></p>
|
||
<p>We’ll talk more about what this means later. For now, it’s enough to know that if you have a function with a non-IO type, like for example <code>myFunction :: Int -> [String] -> String</code>, the function can not have IO happening inside it. It is a pure function.</p>
|
||
<h2 id="control-structures"><span class="header-section-number">11.5</span> Control Structures</h2>
|
||
<p>For the following examples, we’ll need two new operations.</p>
|
||
<div class="sourceCode" id="cb146"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb146-1" data-line-number="1">print<span class="ot"> ::</span> <span class="dt">Show</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- print a value using the show function</span></a>
|
||
<a class="sourceLine" id="cb146-2" data-line-number="2">readLn<span class="ot"> ::</span> <span class="dt">Read</span> a <span class="ot">=></span> <span class="dt">IO</span> a <span class="co">-- get a line and convert it to a value using the read function</span></a></code></pre></div>
|
||
<p>The usual tools of recursion, guards and if-then-else also work in the <code>IO</code> world. Here’s an IO operation that’s defined using a guard:</p>
|
||
<div class="sourceCode" id="cb147"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb147-1" data-line-number="1"><span class="ot">printDescription ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb147-2" data-line-number="2">printDescription n</a>
|
||
<a class="sourceLine" id="cb147-3" data-line-number="3"> <span class="fu">|</span> even n <span class="fu">=</span> putStrLn <span class="st">"even"</span></a>
|
||
<a class="sourceLine" id="cb147-4" data-line-number="4"> <span class="fu">|</span> n<span class="fu">==</span><span class="dv">3</span> <span class="fu">=</span> putStrLn <span class="st">"three"</span></a>
|
||
<a class="sourceLine" id="cb147-5" data-line-number="5"> <span class="fu">|</span> otherwise <span class="fu">=</span> print n</a></code></pre></div>
|
||
<div class="sourceCode" id="cb148"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb148-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> printDescription <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb148-2" data-line-number="2">even</a>
|
||
<a class="sourceLine" id="cb148-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> printDescription <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb148-4" data-line-number="4">three</a>
|
||
<a class="sourceLine" id="cb148-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> printDescription <span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb148-6" data-line-number="6"><span class="dv">5</span></a></code></pre></div>
|
||
<p>Here’s an operation that prints all numbers in a list using recursion and pattern matching:</p>
|
||
<div class="sourceCode" id="cb149"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb149-1" data-line-number="1"><span class="ot">printList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb149-2" data-line-number="2">printList [] <span class="fu">=</span> return () <span class="co">-- do nothing</span></a>
|
||
<a class="sourceLine" id="cb149-3" data-line-number="3">printList (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> print x</a>
|
||
<a class="sourceLine" id="cb149-4" data-line-number="4"> printList xs <span class="co">-- recursion</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb150"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb150-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> printList [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb150-2" data-line-number="2"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb150-3" data-line-number="3"><span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb150-4" data-line-number="4"><span class="dv">3</span></a></code></pre></div>
|
||
<p>Here are two slightly more complicated examples of recursive IO operations. They use the value produced by the recursive call. The operation <code>readAndSum n</code> reads <code>n</code> numbers from the user and prints their sum. The operation <code>ask questions</code> shows each string in <code>questions</code> to the user, reads a response, and returns a list of all the responses.</p>
|
||
<div class="sourceCode" id="cb151"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb151-1" data-line-number="1"><span class="ot">readAndSum ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb151-2" data-line-number="2">readAndSum <span class="dv">0</span> <span class="fu">=</span> return <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb151-3" data-line-number="3">readAndSum n <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb151-4" data-line-number="4"> i <span class="ot"><-</span> readLn <span class="co">-- read one number</span></a>
|
||
<a class="sourceLine" id="cb151-5" data-line-number="5"> s <span class="ot"><-</span> readAndSum (n<span class="fu">-</span><span class="dv">1</span>) <span class="co">-- recursion: read and sum rest of numbers</span></a>
|
||
<a class="sourceLine" id="cb151-6" data-line-number="6"> return (i<span class="fu">+</span>s) <span class="co">-- produce result</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb152"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb152-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> s <span class="ot"><-</span> readAndSum <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb152-2" data-line-number="2"><span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb152-3" data-line-number="3"><span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb152-4" data-line-number="4"><span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb152-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> s</a>
|
||
<a class="sourceLine" id="cb152-6" data-line-number="6"><span class="dv">11</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb153"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb153-1" data-line-number="1"><span class="ot">ask ::</span> [<span class="dt">String</span>] <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb153-2" data-line-number="2">ask [] <span class="fu">=</span> return []</a>
|
||
<a class="sourceLine" id="cb153-3" data-line-number="3">ask (question<span class="fu">:</span>questions) <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb153-4" data-line-number="4"> putStr question</a>
|
||
<a class="sourceLine" id="cb153-5" data-line-number="5"> putStrLn <span class="st">"?"</span></a>
|
||
<a class="sourceLine" id="cb153-6" data-line-number="6"> answer <span class="ot"><-</span> getLine <span class="co">-- get one answer</span></a>
|
||
<a class="sourceLine" id="cb153-7" data-line-number="7"> answers <span class="ot"><-</span> ask questions <span class="co">-- recursion: get rest of answers</span></a>
|
||
<a class="sourceLine" id="cb153-8" data-line-number="8"> return (answer<span class="fu">:</span>answers) <span class="co">-- produce result</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb154"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb154-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> replies <span class="ot"><-</span> ask [<span class="st">"What is your name"</span>,<span class="st">"How old are you"</span>]</a>
|
||
<a class="sourceLine" id="cb154-2" data-line-number="2"><span class="dt">What</span> is your name<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb154-3" data-line-number="3"><span class="dt">Yog</span><span class="fu">-</span><span class="dt">Sothoth</span></a>
|
||
<a class="sourceLine" id="cb154-4" data-line-number="4"><span class="dt">How</span> old are you<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb154-5" data-line-number="5"><span class="dt">The</span> question is meaningless</a>
|
||
<a class="sourceLine" id="cb154-6" data-line-number="6"><span class="dt">Prelude</span><span class="fu">></span> replies</a>
|
||
<a class="sourceLine" id="cb154-7" data-line-number="7">[<span class="st">"Yog-Sothoth"</span>,<span class="st">"The question is meaningless"</span>]</a></code></pre></div>
|
||
<p>Additionally, we have some <code>IO</code>-specific control structures, or rather, functions. These come from the module <code>Control.Monad</code>.</p>
|
||
<div class="sourceCode" id="cb155"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb155-1" data-line-number="1"><span class="co">-- when b op performs op if b is true</span></a>
|
||
<a class="sourceLine" id="cb155-2" data-line-number="2"><span class="ot">when ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">IO</span> () <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb155-3" data-line-number="3"><span class="co">-- unless b op performs op if b is false</span></a>
|
||
<a class="sourceLine" id="cb155-4" data-line-number="4"><span class="ot">unless ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">IO</span> () <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb155-5" data-line-number="5"><span class="co">-- do something many times, collect results</span></a>
|
||
<a class="sourceLine" id="cb155-6" data-line-number="6"><span class="ot">replicateM ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> a <span class="ot">-></span> <span class="dt">IO</span> [a]</a>
|
||
<a class="sourceLine" id="cb155-7" data-line-number="7"><span class="co">-- do something many times, throw away the results</span></a>
|
||
<a class="sourceLine" id="cb155-8" data-line-number="8"><span class="ot">replicateM_ ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> a <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb155-9" data-line-number="9"><span class="co">-- do something for every list element</span></a>
|
||
<a class="sourceLine" id="cb155-10" data-line-number="10">mapM<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">IO</span> [b]</a>
|
||
<a class="sourceLine" id="cb155-11" data-line-number="11"><span class="co">-- do something for every list element, throw away the results</span></a>
|
||
<a class="sourceLine" id="cb155-12" data-line-number="12">mapM_<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb155-13" data-line-number="13"><span class="co">-- the same, but arguments flipped</span></a>
|
||
<a class="sourceLine" id="cb155-14" data-line-number="14"><span class="ot">forM ::</span> [a] <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> <span class="dt">IO</span> [b]</a>
|
||
<a class="sourceLine" id="cb155-15" data-line-number="15"><span class="ot">forM_ ::</span> [a] <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> <span class="dt">IO</span> ()</a></code></pre></div>
|
||
<p>Using these, we can rewrite our earlier examples:</p>
|
||
<div class="sourceCode" id="cb156"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb156-1" data-line-number="1"><span class="ot">printList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb156-2" data-line-number="2">printList xs <span class="fu">=</span> mapM_ print xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb157"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb157-1" data-line-number="1">readAndSum n <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb157-2" data-line-number="2"> numbers <span class="ot"><-</span> replicateM n readLn</a>
|
||
<a class="sourceLine" id="cb157-3" data-line-number="3"> return (sum numbers)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb158"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb158-1" data-line-number="1"><span class="ot">ask ::</span> [<span class="dt">String</span>] <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb158-2" data-line-number="2">ask questions <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb158-3" data-line-number="3"> forM questions askOne</a>
|
||
<a class="sourceLine" id="cb158-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb158-5" data-line-number="5"><span class="ot">askOne ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb158-6" data-line-number="6">askOne question <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb158-7" data-line-number="7"> putStr question</a>
|
||
<a class="sourceLine" id="cb158-8" data-line-number="8"> putStrLn <span class="st">"?"</span></a>
|
||
<a class="sourceLine" id="cb158-9" data-line-number="9"> getLine</a></code></pre></div>
|
||
<h2 id="a-word-about-do-and-indentation"><span class="header-section-number">11.6</span> A Word About <code>do</code> and Indentation</h2>
|
||
<p>It’s easy to run into weird indentation problems when using do-notation. Here are some rules of thumb to help you get it right.</p>
|
||
<p>The most important rule of do and indentation is <em>all operations in a do-block must start in the same column</em>.</p>
|
||
<p>Some examples of this rule:</p>
|
||
<div class="sourceCode" id="cb159"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb159-1" data-line-number="1"><span class="co">-- This is not OK, putStrLn is way too left</span></a>
|
||
<a class="sourceLine" id="cb159-2" data-line-number="2">foo <span class="fu">=</span> <span class="kw">do</span> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb159-3" data-line-number="3"> putStrLn y</a>
|
||
<a class="sourceLine" id="cb159-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb159-5" data-line-number="5"><span class="co">-- This is not OK either</span></a>
|
||
<a class="sourceLine" id="cb159-6" data-line-number="6">foo <span class="fu">=</span> <span class="kw">do</span> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb159-7" data-line-number="7"> putStrLn y</a>
|
||
<a class="sourceLine" id="cb159-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb159-9" data-line-number="9"><span class="co">-- This is OK</span></a>
|
||
<a class="sourceLine" id="cb159-10" data-line-number="10">foo <span class="fu">=</span> <span class="kw">do</span> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb159-11" data-line-number="11"> putStrLn y</a>
|
||
<a class="sourceLine" id="cb159-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb159-13" data-line-number="13"><span class="co">-- This is also OK: putting a line break after do</span></a>
|
||
<a class="sourceLine" id="cb159-14" data-line-number="14">foo <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb159-15" data-line-number="15"> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb159-16" data-line-number="16"> putStrLn y</a></code></pre></div>
|
||
<p>A related rule is <em>when an operation goes over multiple lines, indent the follow-up lines</em>. If you don’t indent, it’ll look like a new operation!</p>
|
||
<div class="sourceCode" id="cb160"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb160-1" data-line-number="1"><span class="co">-- This is not OK, the string starts a new operation</span></a>
|
||
<a class="sourceLine" id="cb160-2" data-line-number="2">quux <span class="fu">=</span> <span class="kw">do</span> putStrLn</a>
|
||
<a class="sourceLine" id="cb160-3" data-line-number="3"> <span class="st">"this long string"</span></a>
|
||
<a class="sourceLine" id="cb160-4" data-line-number="4"> print <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb160-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb160-6" data-line-number="6"><span class="co">-- This is OK</span></a>
|
||
<a class="sourceLine" id="cb160-7" data-line-number="7">quux <span class="fu">=</span> <span class="kw">do</span> putStrLn</a>
|
||
<a class="sourceLine" id="cb160-8" data-line-number="8"> <span class="st">"this long string"</span></a>
|
||
<a class="sourceLine" id="cb160-9" data-line-number="9"> print <span class="dv">1</span></a></code></pre></div>
|
||
<p>Here’s one more example, with nested do-blocks, and two different valid indentations.</p>
|
||
<div class="sourceCode" id="cb161"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb161-1" data-line-number="1"><span class="co">-- This is OK</span></a>
|
||
<a class="sourceLine" id="cb161-2" data-line-number="2">foo x <span class="fu">=</span> <span class="kw">do</span> quux</a>
|
||
<a class="sourceLine" id="cb161-3" data-line-number="3"> y <span class="ot"><-</span> blorg</a>
|
||
<a class="sourceLine" id="cb161-4" data-line-number="4"> when y (<span class="kw">do</span> thing</a>
|
||
<a class="sourceLine" id="cb161-5" data-line-number="5"> otherThing)</a>
|
||
<a class="sourceLine" id="cb161-6" data-line-number="6"> return <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb161-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb161-8" data-line-number="8"><span class="co">-- This is also OK: starting putting a line break after do, using $</span></a>
|
||
<a class="sourceLine" id="cb161-9" data-line-number="9">foo x <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb161-10" data-line-number="10"> quux</a>
|
||
<a class="sourceLine" id="cb161-11" data-line-number="11"> y <span class="ot"><-</span> blorg</a>
|
||
<a class="sourceLine" id="cb161-12" data-line-number="12"> when y <span class="fu">$</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb161-13" data-line-number="13"> thing</a>
|
||
<a class="sourceLine" id="cb161-14" data-line-number="14"> otherThing</a>
|
||
<a class="sourceLine" id="cb161-15" data-line-number="15"> return <span class="dv">3</span></a></code></pre></div>
|
||
<h2 id="lets-write-a-program"><span class="header-section-number">11.7</span> Let’s Write a Program</h2>
|
||
<p>After all these short one-off examples, let’s turn to something a bit longer. Let’s write a program to fetch all type annotations from all <code>.hs</code> files. We use IO operations like <code>readFile</code> and <code>listDirectory</code> to read and find files, but also pure code like <code>map</code> and <code>filter</code> to do the actual processing. First off, here’s a recap of the library operations we’re using:</p>
|
||
<div class="sourceCode" id="cb162"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb162-1" data-line-number="1"><span class="co">-- split string into lines</span></a>
|
||
<a class="sourceLine" id="cb162-2" data-line-number="2">lines<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb162-3" data-line-number="3"><span class="co">-- `isSuffixOf suf list` is true if list ends in suf</span></a>
|
||
<a class="sourceLine" id="cb162-4" data-line-number="4">Data.List.isSuffixOf<span class="ot"> ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb162-5" data-line-number="5"><span class="co">-- `isInfixOf inf list` is true if inf occurs inside list</span></a>
|
||
<a class="sourceLine" id="cb162-6" data-line-number="6">Data.List.isInfixOf<span class="ot"> ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb162-7" data-line-number="7"><span class="co">-- FilePath is just an alias for String</span></a>
|
||
<a class="sourceLine" id="cb162-8" data-line-number="8"><span class="kw">type</span> FilePath <span class="fu">=</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb162-9" data-line-number="9"><span class="co">-- get entire contents of file</span></a>
|
||
<a class="sourceLine" id="cb162-10" data-line-number="10">readFile<span class="ot"> ::</span> FilePath <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb162-11" data-line-number="11"><span class="co">-- list files in directory</span></a>
|
||
<a class="sourceLine" id="cb162-12" data-line-number="12">System.Directory.listDirectory<span class="ot"> ::</span> FilePath <span class="ot">-></span> <span class="dt">IO</span> [FilePath]</a>
|
||
<a class="sourceLine" id="cb162-13" data-line-number="13"><span class="co">-- is the given file a directory?</span></a>
|
||
<a class="sourceLine" id="cb162-14" data-line-number="14">System.Directory.doesDirectoryExist<span class="ot"> ::</span> FilePath <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></a></code></pre></div>
|
||
<p>And here’s the program itself. You can also find it in the course repository as <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Example/ReadTypes.hs"><code>exercises/Examples/ReadTypes.hs</code></a>.</p>
|
||
<div class="sourceCode" id="cb163"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb163-1" data-line-number="1"><span class="kw">module</span> <span class="dt">Examples.ReadTypes</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb163-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb163-3" data-line-number="3"><span class="kw">import</span> <span class="dt">Control.Monad</span> (forM)</a>
|
||
<a class="sourceLine" id="cb163-4" data-line-number="4"><span class="kw">import</span> <span class="dt">Data.List</span> (isInfixOf, isSuffixOf)</a>
|
||
<a class="sourceLine" id="cb163-5" data-line-number="5"><span class="kw">import</span> <span class="dt">System.Directory</span> (listDirectory, doesDirectoryExist)</a>
|
||
<a class="sourceLine" id="cb163-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb163-7" data-line-number="7"><span class="co">-- a line is a type signature if it contains :: but does not contain =</span></a>
|
||
<a class="sourceLine" id="cb163-8" data-line-number="8"><span class="ot">isTypeSignature ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb163-9" data-line-number="9">isTypeSignature s <span class="fu">=</span> not (isInfixOf <span class="st">"="</span> s) <span class="fu">&&</span> isInfixOf <span class="st">"::"</span> s</a>
|
||
<a class="sourceLine" id="cb163-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb163-11" data-line-number="11"><span class="co">-- return list of types for a .hs file</span></a>
|
||
<a class="sourceLine" id="cb163-12" data-line-number="12"><span class="ot">readTypesFile ::</span> FilePath <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb163-13" data-line-number="13">readTypesFile file</a>
|
||
<a class="sourceLine" id="cb163-14" data-line-number="14"> <span class="fu">|</span> isSuffixOf <span class="st">".hs"</span> file <span class="fu">=</span> <span class="kw">do</span> content <span class="ot"><-</span> readFile file</a>
|
||
<a class="sourceLine" id="cb163-15" data-line-number="15"> <span class="kw">let</span> ls <span class="fu">=</span> lines content</a>
|
||
<a class="sourceLine" id="cb163-16" data-line-number="16"> return (filter isTypeSignature ls)</a>
|
||
<a class="sourceLine" id="cb163-17" data-line-number="17"> <span class="fu">|</span> otherwise <span class="fu">=</span> return []</a>
|
||
<a class="sourceLine" id="cb163-18" data-line-number="18"></a>
|
||
<a class="sourceLine" id="cb163-19" data-line-number="19"><span class="co">-- list children of directory, prepend directory name</span></a>
|
||
<a class="sourceLine" id="cb163-20" data-line-number="20"><span class="ot">qualifiedChildren ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb163-21" data-line-number="21">qualifiedChildren path <span class="fu">=</span> <span class="kw">do</span> childs <span class="ot"><-</span> listDirectory path</a>
|
||
<a class="sourceLine" id="cb163-22" data-line-number="22"> return (map (\name <span class="ot">-></span> path<span class="fu">++</span><span class="st">"/"</span><span class="fu">++</span>name) childs)</a>
|
||
<a class="sourceLine" id="cb163-23" data-line-number="23"></a>
|
||
<a class="sourceLine" id="cb163-24" data-line-number="24"><span class="co">-- get type signatures for all entries in given directory</span></a>
|
||
<a class="sourceLine" id="cb163-25" data-line-number="25"><span class="co">-- note mutual recursion with readTypes</span></a>
|
||
<a class="sourceLine" id="cb163-26" data-line-number="26"><span class="ot">readTypesDir ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb163-27" data-line-number="27">readTypesDir path <span class="fu">=</span> <span class="kw">do</span> childs <span class="ot"><-</span> qualifiedChildren path</a>
|
||
<a class="sourceLine" id="cb163-28" data-line-number="28"> typess <span class="ot"><-</span> forM childs readTypes</a>
|
||
<a class="sourceLine" id="cb163-29" data-line-number="29"> return (concat typess)</a>
|
||
<a class="sourceLine" id="cb163-30" data-line-number="30"></a>
|
||
<a class="sourceLine" id="cb163-31" data-line-number="31"><span class="co">-- recursively read types contained in a file or directory</span></a>
|
||
<a class="sourceLine" id="cb163-32" data-line-number="32"><span class="co">-- note mutual recursion with readTypesDir</span></a>
|
||
<a class="sourceLine" id="cb163-33" data-line-number="33"><span class="ot">readTypes ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb163-34" data-line-number="34">readTypes path <span class="fu">=</span> <span class="kw">do</span> isDir <span class="ot"><-</span> doesDirectoryExist path</a>
|
||
<a class="sourceLine" id="cb163-35" data-line-number="35"> <span class="kw">if</span> isDir <span class="kw">then</span> readTypesDir path <span class="kw">else</span> readTypesFile path</a>
|
||
<a class="sourceLine" id="cb163-36" data-line-number="36"></a>
|
||
<a class="sourceLine" id="cb163-37" data-line-number="37"><span class="co">-- main is the IO action that gets run when you run the program</span></a>
|
||
<a class="sourceLine" id="cb163-38" data-line-number="38"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb163-39" data-line-number="39">main <span class="fu">=</span> <span class="kw">do</span> ts <span class="ot"><-</span> readTypes <span class="st">"."</span></a>
|
||
<a class="sourceLine" id="cb163-40" data-line-number="40"> mapM_ putStrLn ts</a></code></pre></div>
|
||
<p>We can run this program by going to the directory <code>exercises/Examples</code> and running:</p>
|
||
<div class="sourceCode" id="cb164"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb164-1" data-line-number="1"><span class="fu">$</span> stack runhaskell ReadTypes.hs</a>
|
||
<a class="sourceLine" id="cb164-2" data-line-number="2"><span class="ot">deposit ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> <span class="dt">Bank</span></a>
|
||
<a class="sourceLine" id="cb164-3" data-line-number="3"><span class="ot">withdraw ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> (<span class="dt">Int</span>,<span class="dt">Bank</span>)</a>
|
||
<a class="sourceLine" id="cb164-4" data-line-number="4"><span class="ot">runBankOp ::</span> <span class="dt">BankOp</span> a <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> (a,<span class="dt">Bank</span>)</a>
|
||
<a class="sourceLine" id="cb164-5" data-line-number="5"><span class="fu">...</span> and so on</a></code></pre></div>
|
||
<p>The exact output will vary according to the contents of the directory, of course.</p>
|
||
<h2 id="what-does-it-all-mean"><span class="header-section-number">11.8</span> What Does It All Mean?</h2>
|
||
<p>Let’s return to the functional world. How can we reconcile IO operations with Haskell being a <em>pure</em> and <em>lazy</em> language? Something like <code>putStrLn :: String -> IO ()</code> is a <em>pure</em> function that returns an operation. How is it pure? <code>putStrLn x</code> is the same when <code>x</code> is the same. In other words: an operation is a <em>pure description</em> of a chain of side effects. Only <em>executing</em> the operation causes those side effects. When a Haskell program is run, only one operation is executed - it’s called <code>main :: IO ()</code>. Other operations can be run only by linking them up to <code>main</code>.</p>
|
||
<p>When in GHCi, if an expression you type in evaluates to an operation, GHCi runs that operation for you. Here’s a demonstration of the purity of <code>print</code>:</p>
|
||
<div class="sourceCode" id="cb165"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb165-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">let</span> x <span class="fu">=</span> print <span class="dv">1</span> <span class="co">-- creates operation, doesn't run it</span></a>
|
||
<a class="sourceLine" id="cb165-2" data-line-number="2"><span class="dt">Prelude</span><span class="fu">></span> x <span class="co">-- runs the operation</span></a>
|
||
<a class="sourceLine" id="cb165-3" data-line-number="3"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb165-4" data-line-number="4"><span class="dt">Prelude</span><span class="fu">></span> x <span class="co">-- runs it again!</span></a>
|
||
<a class="sourceLine" id="cb165-5" data-line-number="5"><span class="dv">1</span></a></code></pre></div>
|
||
<p><em>Operations are values</em> just like numbers, lists and functions. We can write code that operates on operations. This function takes two operations, <code>a</code> and <code>b</code>, and returns an operation that asks the user which one he’d like to run.</p>
|
||
<div class="sourceCode" id="cb166"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb166-1" data-line-number="1"><span class="ot">choice ::</span> <span class="dt">IO</span> x <span class="ot">-></span> <span class="dt">IO</span> x <span class="ot">-></span> <span class="dt">IO</span> x</a>
|
||
<a class="sourceLine" id="cb166-2" data-line-number="2">choice a b <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb166-3" data-line-number="3"> <span class="kw">do</span> putStr <span class="st">"a or b? "</span></a>
|
||
<a class="sourceLine" id="cb166-4" data-line-number="4"> x <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb166-5" data-line-number="5"> <span class="kw">case</span> x <span class="kw">of</span> <span class="st">"a"</span> <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb166-6" data-line-number="6"> <span class="st">"b"</span> <span class="ot">-></span> b</a>
|
||
<a class="sourceLine" id="cb166-7" data-line-number="7"> _ <span class="ot">-></span> <span class="kw">do</span> putStrLn <span class="st">"Wrong!"</span></a>
|
||
<a class="sourceLine" id="cb166-8" data-line-number="8"> choice a b</a></code></pre></div>
|
||
<div class="sourceCode" id="cb167"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb167-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> choice (putStrLn <span class="st">"A!!!!"</span>) (putStrLn <span class="st">"B!!!!"</span>)</a>
|
||
<a class="sourceLine" id="cb167-2" data-line-number="2">a or b<span class="fu">?</span> z</a>
|
||
<a class="sourceLine" id="cb167-3" data-line-number="3"><span class="dt">Wrong</span><span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb167-4" data-line-number="4">a or b<span class="fu">?</span> a</a>
|
||
<a class="sourceLine" id="cb167-5" data-line-number="5"><span class="dt">A</span><span class="fu">!!!!</span></a></code></pre></div>
|
||
<p>Using operations specified as parameters lets us write functions like <code>mapM_</code>, which we met earlier. The implementation is a recursive IO operation that takes another IO operation as a parameter. Conceptually complicated, but simple when you read the code:</p>
|
||
<div class="sourceCode" id="cb168"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb168-1" data-line-number="1">mapM_<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb168-2" data-line-number="2">mapM_ op [] <span class="fu">=</span> return () <span class="co">-- do nothing for an empty list</span></a>
|
||
<a class="sourceLine" id="cb168-3" data-line-number="3">mapM_ op (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> op x <span class="co">-- run operation on first element</span></a>
|
||
<a class="sourceLine" id="cb168-4" data-line-number="4"> mapM_ op xs <span class="co">-- run operation on rest of list, recursively</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb169"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb169-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> mapM_ print [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb169-2" data-line-number="2"><span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb169-3" data-line-number="3"><span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb169-4" data-line-number="4"><span class="dv">3</span></a></code></pre></div>
|
||
<h2 id="one-more-thing-ioref"><span class="header-section-number">11.9</span> One More Thing: IORef</h2>
|
||
<p>So far the only side-effects we’ve been able to produce in IO have been terminal (<code>getLine</code>, <code>print</code>) and file (<code>readFile</code>, <code>listDirectory</code>) IO. Imperative programs written in Java, Python or C have other types of side effects too that we can’t express in pure Haskell. One of these is <em>mutable (i.e. changeable) state</em>. A pure function can not read mutable state, because otherwise two invocations of the same function might not return the same value.</p>
|
||
<p>The Haskell type <code>IORef a</code> from the module <code>Data.IORef</code> is a mutable reference to a value of type <code>a</code></p>
|
||
<div class="sourceCode" id="cb170"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb170-1" data-line-number="1"><span class="ot">newIORef ::</span> a <span class="ot">-></span> <span class="dt">IO</span> (<span class="dt">IORef</span> a) <span class="co">-- create a new IORef containing a value</span></a>
|
||
<a class="sourceLine" id="cb170-2" data-line-number="2"><span class="ot">readIORef ::</span> <span class="dt">IORef</span> a <span class="ot">-></span> <span class="dt">IO</span> a <span class="co">-- produce value contained in IORef</span></a>
|
||
<a class="sourceLine" id="cb170-3" data-line-number="3"><span class="ot">writeIORef ::</span> <span class="dt">IORef</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- set value in IORef</span></a>
|
||
<a class="sourceLine" id="cb170-4" data-line-number="4"><span class="ot">modifyIORef ::</span> <span class="dt">IORef</span> a <span class="ot">-></span> (a <span class="ot">-></span> a) <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- modify value contained in IORef with a pure function</span></a></code></pre></div>
|
||
<p>Here are some examples of using an IORef in GHCi:</p>
|
||
<div class="sourceCode" id="cb171"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb171-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>m <span class="fu">+</span><span class="dt">Data.IORef</span></a>
|
||
<a class="sourceLine" id="cb171-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> myRef <span class="ot"><-</span> newIORef <span class="st">"banana"</span></a>
|
||
<a class="sourceLine" id="cb171-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> readIORef myRef</a>
|
||
<a class="sourceLine" id="cb171-4" data-line-number="4"><span class="st">"banana"</span></a>
|
||
<a class="sourceLine" id="cb171-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> writeIORef myRef <span class="st">"apple"</span></a>
|
||
<a class="sourceLine" id="cb171-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> readIORef myRef</a>
|
||
<a class="sourceLine" id="cb171-7" data-line-number="7"><span class="st">"apple"</span></a>
|
||
<a class="sourceLine" id="cb171-8" data-line-number="8"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> modifyIORef myRef reverse</a>
|
||
<a class="sourceLine" id="cb171-9" data-line-number="9"><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="fu">></span> readIORef myRef</a>
|
||
<a class="sourceLine" id="cb171-10" data-line-number="10"><span class="st">"elppa"</span></a></code></pre></div>
|
||
<p>Here’s an example of using an <code>IORef</code> to sum the values in a list. Note the similarity with an imperative loop.</p>
|
||
<div class="sourceCode" id="cb172"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb172-1" data-line-number="1"><span class="ot">sumList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb172-2" data-line-number="2">sumList xs <span class="fu">=</span> <span class="kw">do</span> r <span class="ot"><-</span> newIORef <span class="dv">0</span> <span class="co">-- initialize r to 0</span></a>
|
||
<a class="sourceLine" id="cb172-3" data-line-number="3"> forM_ xs (\x <span class="ot">-></span> modifyIORef r (x<span class="fu">+</span>)) <span class="co">-- for every xs, add it to r</span></a>
|
||
<a class="sourceLine" id="cb172-4" data-line-number="4"> readIORef r <span class="co">-- get last value of r</span></a></code></pre></div>
|
||
<p>Using <code>IORef</code> isn’t necessary most of the time. Haskell style prefers recursion, arguments and return values. However real world programs might need one or two IORefs occasionally.</p>
|
||
<h2 id="summary-of-io"><span class="header-section-number">11.10</span> Summary of IO</h2>
|
||
<p>A value of type <code>IO X</code> is an <em>IO operation</em> that <em>produces</em> a value of type X <em>when run</em>. Operations are pure values. Only <em>running</em> the operation causes the side effects.</p>
|
||
<p>IO operations can combined together using <code>do</code>-notation:</p>
|
||
<div class="sourceCode" id="cb173"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb173-1" data-line-number="1"><span class="ot">op ::</span> <span class="dt">X</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Y</span></a>
|
||
<a class="sourceLine" id="cb173-2" data-line-number="2">op arg <span class="fu">=</span> <span class="kw">do</span> operation <span class="co">-- run operation</span></a>
|
||
<a class="sourceLine" id="cb173-3" data-line-number="3"> operation2 arg <span class="co">-- run operation with argument</span></a>
|
||
<a class="sourceLine" id="cb173-4" data-line-number="4"> result <span class="ot"><-</span> operation3 arg <span class="co">-- run operation with argument, store result</span></a>
|
||
<a class="sourceLine" id="cb173-5" data-line-number="5"> <span class="kw">let</span> something <span class="fu">=</span> f result <span class="co">-- run a pure function f, store result</span></a>
|
||
<a class="sourceLine" id="cb173-6" data-line-number="6"> finalOperation <span class="co">-- last operation produces the the return value</span></a></code></pre></div>
|
||
<p>The <code>return x</code> operation is an operation that always produces value <code>x</code>. When <code>x :: a</code>, <code>return x :: IO a</code>.</p>
|
||
<p>Useful IO operations:</p>
|
||
<div class="sourceCode" id="cb174"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb174-1" data-line-number="1"><span class="co">-- printing & reading</span></a>
|
||
<a class="sourceLine" id="cb174-2" data-line-number="2">putStr<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb174-3" data-line-number="3">putStrLn<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb174-4" data-line-number="4">print<span class="ot"> ::</span> <span class="dt">Show</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb174-5" data-line-number="5">getLine<span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb174-6" data-line-number="6">readLn<span class="ot"> ::</span> <span class="dt">Read</span> a <span class="ot">=></span> <span class="dt">IO</span> a</a>
|
||
<a class="sourceLine" id="cb174-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb174-8" data-line-number="8"><span class="co">-- control structures from Control.Monad</span></a>
|
||
<a class="sourceLine" id="cb174-9" data-line-number="9"><span class="ot">when ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">IO</span> () <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- when b op performs op if b is true</span></a>
|
||
<a class="sourceLine" id="cb174-10" data-line-number="10"><span class="ot">unless ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">IO</span> () <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- unless b op performs op if b is false</span></a>
|
||
<a class="sourceLine" id="cb174-11" data-line-number="11"><span class="ot">replicateM ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> a <span class="ot">-></span> <span class="dt">IO</span> [a] <span class="co">-- do something many times, collect results</span></a>
|
||
<a class="sourceLine" id="cb174-12" data-line-number="12"><span class="ot">replicateM_ ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> a <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- do something many times, throw away the results</span></a>
|
||
<a class="sourceLine" id="cb174-13" data-line-number="13">mapM<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">IO</span> [b] <span class="co">-- do something for every list element</span></a>
|
||
<a class="sourceLine" id="cb174-14" data-line-number="14">mapM_<span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">IO</span> () <span class="co">-- do something for every list element, throw away the results</span></a>
|
||
<a class="sourceLine" id="cb174-15" data-line-number="15"><span class="ot">forM ::</span> [a] <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> <span class="dt">IO</span> [b] <span class="co">-- the same, but arguments flipped</span></a>
|
||
<a class="sourceLine" id="cb174-16" data-line-number="16"><span class="ot">forM_ ::</span> [a] <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">IO</span> b) <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb174-17" data-line-number="17"></a>
|
||
<a class="sourceLine" id="cb174-18" data-line-number="18"><span class="co">-- files</span></a>
|
||
<a class="sourceLine" id="cb174-19" data-line-number="19">readFile<span class="ot"> ::</span> FilePath <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a></code></pre></div>
|
||
<h2 id="quiz-2"><span class="header-section-number">11.11</span> Quiz</h2>
|
||
<p>What is the type of this IO operation?</p>
|
||
<div class="sourceCode" id="cb175"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb175-1" data-line-number="1">foo x <span class="fu">=</span> <span class="kw">do</span> putStrLn x</a>
|
||
<a class="sourceLine" id="cb175-2" data-line-number="2"> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb175-3" data-line-number="3"> return (length y)</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>String -> IO String</code>
|
||
</li>
|
||
<li>
|
||
<code>IO Int</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>String -> IO Int</code>
|
||
</li>
|
||
<li>
|
||
<code>IO String -> IO Int</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these lines could be used in place of <code>????</code></p>
|
||
<div class="sourceCode" id="cb176"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb176-1" data-line-number="1"><span class="ot">quux ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb176-2" data-line-number="2">quux q <span class="fu">=</span> <span class="kw">do</span> y <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb176-3" data-line-number="3"> z <span class="ot"><-</span> getLine</a>
|
||
<a class="sourceLine" id="cb176-4" data-line-number="4"> putStrLn (y<span class="fu">++</span>z)</a>
|
||
<a class="sourceLine" id="cb176-5" data-line-number="5"> <span class="fu">????</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>q <- getLine</code>
|
||
</li>
|
||
<li>
|
||
<code>return (y++z)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>return [q]</code>
|
||
</li>
|
||
<li>
|
||
<code>ans <- return [y,z]</code>
|
||
</li>
|
||
</ol>
|
||
<p>What values does <code>blorg [1,2,3]</code> print?</p>
|
||
<div class="sourceCode" id="cb177"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb177-1" data-line-number="1">blorg [] <span class="fu">=</span> return <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb177-2" data-line-number="2">blorg (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> m <span class="ot"><-</span> blorg xs</a>
|
||
<a class="sourceLine" id="cb177-3" data-line-number="3"> print x</a>
|
||
<a class="sourceLine" id="cb177-4" data-line-number="4"> return (m<span class="fu">+</span>x)</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
It prints <code>1</code>, <code>2</code>, <code>3</code>
|
||
</li>
|
||
<li>
|
||
It prints <code>1</code>, <code>2</code>, <code>3</code>, <code>6</code>
|
||
</li>
|
||
<li class="correct">
|
||
It prints <code>3</code>, <code>2</code>, <code>1</code>
|
||
</li>
|
||
<li>
|
||
It prints <code>3</code>, <code>2</code>, <code>1</code>, <code>6</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these can a function of type <code>Int -> IO Int</code> do?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
No function of this type can be defined.
|
||
</li>
|
||
<li>
|
||
Return a constant value.
|
||
</li>
|
||
<li>
|
||
Run the IO operation it has been given and return its value.
|
||
</li>
|
||
<li class="correct">
|
||
Query the user for a number and return it.
|
||
</li>
|
||
</ol>
|
||
<p>Which of these can a function of type <code>IO Int -> Int</code> do?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
No function of this type can be defined.
|
||
</li>
|
||
<li class="correct">
|
||
Return a constant value.
|
||
</li>
|
||
<li>
|
||
Run the IO operation it has been given and return its value.
|
||
</li>
|
||
<li>
|
||
Query the user for a number and return it.
|
||
</li>
|
||
</ol>
|
||
<h2 id="exercises-2"><span class="header-section-number">11.12</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set11a.hs">Set11a</a> - basic IO exercises</li>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set11b.hs">Set11b</a> - advanced IO exercises</li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
<h1 id="lecture-12-fmap-fmap-fmap"><span class="header-section-number">12</span> Lecture 12: fmap fmap fmap</h1>
|
||
<h2 id="contents-1"><span class="header-section-number">12.1</span> Contents</h2>
|
||
<ul>
|
||
<li>Functors</li>
|
||
</ul>
|
||
<h2 id="functors"><span class="header-section-number">12.2</span> Functors</h2>
|
||
<h3 id="preserving-structure"><span class="header-section-number">12.2.1</span> Preserving Structure</h3>
|
||
<p>Remember the <code>map</code> function for lists? Here’s the definition again:</p>
|
||
<div class="sourceCode" id="cb178"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb178-1" data-line-number="1">map<span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</a>
|
||
<a class="sourceLine" id="cb178-2" data-line-number="2">map _ [] <span class="fu">=</span> []</a>
|
||
<a class="sourceLine" id="cb178-3" data-line-number="3">map g (x<span class="fu">:</span>xs) <span class="fu">=</span> g x <span class="fu">:</span> map g xs</a></code></pre></div>
|
||
<p>It applies a function <code>g :: a -> b</code> to each element of a list of type <code>[a]</code>, returning a list of type <code>[b]</code>. Another way to express the type of <code>map</code> would be <code>(a -> b) -> ([a] -> [b])</code>. This is the same type because <code>-></code> associates to right. The extra parentheses emphasize the fact that <code>map</code> converts the function <code>g :: a -> b</code> into a function <code>map g :: [a] -> [b]</code>. This means that <code>map</code> is a <em>higher-order function</em> that transforms functions to functions.</p>
|
||
<p>As <code>map</code> is parametrically polymorphic, its definition doesn’t depend on the type of values stored in the list. Thus, every function of type <code>a -> b</code> is converted into a function of type <code>[a] -> [b]</code> using exactly the same logic. Using the definition above, we can see that:</p>
|
||
<div class="sourceCode" id="cb179"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb179-1" data-line-number="1">map (<span class="fu">||</span> <span class="dt">True</span>) [<span class="dt">True</span>, <span class="dt">True</span>, <span class="dt">False</span>]</a>
|
||
<a class="sourceLine" id="cb179-2" data-line-number="2"> <span class="fu">==></span> [<span class="dt">True</span> <span class="fu">||</span> <span class="dt">True</span>, <span class="dt">True</span> <span class="fu">||</span> <span class="dt">True</span>, <span class="dt">False</span> <span class="fu">||</span> <span class="dt">True</span>]</a>
|
||
<a class="sourceLine" id="cb179-3" data-line-number="3"> <span class="fu">==></span> [<span class="dt">True</span>, <span class="dt">True</span>, <span class="dt">True</span>]</a>
|
||
<a class="sourceLine" id="cb179-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb179-5" data-line-number="5">map (<span class="fu">+</span><span class="dv">1</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb179-6" data-line-number="6"> <span class="fu">==></span> [<span class="dv">1</span> <span class="fu">+</span> <span class="dv">1</span>, <span class="dv">2</span> <span class="fu">+</span> <span class="dv">1</span>, <span class="dv">3</span> <span class="fu">+</span> <span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb179-7" data-line-number="7"> <span class="fu">==></span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb179-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb179-9" data-line-number="9">map (<span class="fu">++</span><span class="st">"1"</span>) [<span class="st">"1"</span>, <span class="st">"2"</span>, <span class="st">"3"</span>]</a>
|
||
<a class="sourceLine" id="cb179-10" data-line-number="10"> <span class="fu">==></span> [<span class="st">"1"</span> <span class="fu">++</span> <span class="st">"1"</span>, <span class="st">"2"</span> <span class="fu">++</span> <span class="st">"1"</span>, <span class="st">"3"</span> <span class="fu">++</span> <span class="st">"1"</span>]</a>
|
||
<a class="sourceLine" id="cb179-11" data-line-number="11"> <span class="fu">==></span> [<span class="st">"11"</span>, <span class="st">"21"</span>, <span class="st">"31"</span>]</a></code></pre></div>
|
||
<p>What’s notable here is that <code>map</code> <em>preserves the structure</em> of a list. The length of the list and the relative positions of the elements are the same. The general idea is demonstrated in the picture below.</p>
|
||
<figure>
|
||
<img src="img/map.svg" alt="Mapping a function to a list" /><figcaption>Mapping a function to a list</figcaption>
|
||
</figure>
|
||
<p>Let’s see if we can find other similar functions. A value of type <code>Maybe a</code> is kind of like a list of length at most 1. Let’s map over a <code>Maybe</code>! Can you see the similarity with the definition of <code>map</code>?</p>
|
||
<div class="sourceCode" id="cb180"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb180-1" data-line-number="1"><span class="ot">mapMaybe ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Maybe</span> a <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb180-2" data-line-number="2">mapMaybe f <span class="dt">Nothing</span> <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb180-3" data-line-number="3">mapMaybe f (<span class="dt">Just</span> x) <span class="fu">=</span> <span class="dt">Just</span> (f x)</a></code></pre></div>
|
||
<p>Here too, the structure of the value is preserved. A <code>Nothing</code> turns into a <code>Nothing</code>, and a <code>Just</code> turns into a <code>Just</code>. Here too, we can think of the type as <code>(a -> b) -> (Maybe a -> Maybe b)</code>, converting (or “lifting”) a normal function into a function that works on Maybes.</p>
|
||
<p>One more example: consider binary trees.</p>
|
||
<div class="sourceCode" id="cb181"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb181-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Tree</span> a <span class="fu">=</span> <span class="dt">Leaf</span> <span class="fu">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</a>
|
||
<a class="sourceLine" id="cb181-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb181-3" data-line-number="3"><span class="ot">mapTree ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Tree</span> a <span class="ot">-></span> <span class="dt">Tree</span> b</a>
|
||
<a class="sourceLine" id="cb181-4" data-line-number="4">mapTree f <span class="dt">Leaf</span> <span class="fu">=</span> <span class="dt">Leaf</span></a>
|
||
<a class="sourceLine" id="cb181-5" data-line-number="5">mapTree f (<span class="dt">Node</span> val left right) <span class="fu">=</span> <span class="dt">Node</span> (f val) (mapTree f left) (mapTree f right)</a></code></pre></div>
|
||
<p>A binary tree might look like this:</p>
|
||
<figure>
|
||
<img src="img/mapTreeBefore.svg" alt="A binary tree" /><figcaption>A binary tree</figcaption>
|
||
</figure>
|
||
<p>After <code>mapTree f</code> the tree would looke like this:</p>
|
||
<figure>
|
||
<img src="img/mapTreeAfter.svg" alt="A binary tree after mapping" /><figcaption>A binary tree after mapping</figcaption>
|
||
</figure>
|
||
<h3 id="the-functor-class"><span class="header-section-number">12.2.2</span> The <code>Functor</code> Class</h3>
|
||
<p>Now we have three different structure-preserving mapping functions. Three similar operations over different types. Could we write a type class to capture this similarity?</p>
|
||
<div class="sourceCode" id="cb182"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb182-1" data-line-number="1">map<span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</a>
|
||
<a class="sourceLine" id="cb182-2" data-line-number="2"><span class="ot">mapMaybe ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Maybe</span> a <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb182-3" data-line-number="3"><span class="ot">mapTree ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Tree</span> a <span class="ot">-></span> <span class="dt">Tree</span> b</a></code></pre></div>
|
||
<p>A naive attempt at writing a type class runs into problems. If we try to abstract over <code>Maybe c</code>, we can’t seem to write the right type for the map operation. We’d need to be able to change the type parameter <code>c</code> somehow.</p>
|
||
<div class="sourceCode" id="cb183"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb183-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Mappable</span> m <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb183-2" data-line-number="2"><span class="ot"> mapThing ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> m <span class="ot">-></span> m</a>
|
||
<a class="sourceLine" id="cb183-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb183-4" data-line-number="4"><span class="kw">instance</span> <span class="dt">Mappable</span> (<span class="dt">Maybe</span> c) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb183-5" data-line-number="5"><span class="ot"> mapThing ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Maybe</span> c <span class="ot">-></span> <span class="dt">Maybe</span> c</a>
|
||
<a class="sourceLine" id="cb183-6" data-line-number="6"> mapThing <span class="fu">=</span> <span class="fu">...</span></a></code></pre></div>
|
||
<p>Luckily Haskell type classes have a feature we haven’t covered before. You can write classes for <em>type constructors</em> in addition to types. What does this mean? Let’s just have a look at the standard type class <code>Functor</code> that does what we tried to do with our <code>Mappable</code>.</p>
|
||
<div class="sourceCode" id="cb184"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb184-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Functor</span> f <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb184-2" data-line-number="2"><span class="ot"> fmap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</a></code></pre></div>
|
||
<p>Note how the type parameter <code>f</code> is a type constructor: it’s being passed <code>a</code> and <code>b</code> arguments in different parts of the type of <code>fmap</code>. Now let’s see the instance for <code>Maybe</code>.</p>
|
||
<div class="sourceCode" id="cb185"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb185-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Maybe</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb185-2" data-line-number="2"><span class="ot"> fmap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> <span class="dt">Maybe</span> a <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb185-3" data-line-number="3"> fmap f <span class="dt">Nothing</span> <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb185-4" data-line-number="4"> fmap f (<span class="dt">Just</span> x) <span class="fu">=</span> <span class="dt">Just</span> (f x)</a></code></pre></div>
|
||
<p>Now <code>fmap</code> has the right type and we can implement it like <code>mapMaybe</code>! Note how we’ve declared <code>instance Functor Maybe</code> instead of <code>instance Functor (Maybe a)</code>. The type <code>Maybe a</code> isn’t a functor, the type constructor <code>Maybe</code> is.</p>
|
||
<p>The type constructor for lists is written <code>[]</code>. It’s special syntax, just like other list syntax. However if the type <code>[a]</code> was written <code>List a</code>, the type constructor <code>[]</code> would mean <code>List</code>.</p>
|
||
<div class="sourceCode" id="cb186"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb186-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Functor</span> [] <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb186-2" data-line-number="2"> fmap <span class="fu">=</span> map</a></code></pre></div>
|
||
<p>Here’s the final of our examples, as a <code>Functor</code> instance.</p>
|
||
<div class="sourceCode" id="cb187"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb187-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Tree</span> a <span class="fu">=</span> <span class="dt">Leaf</span> <span class="fu">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</a>
|
||
<a class="sourceLine" id="cb187-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb187-3" data-line-number="3"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Tree</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb187-4" data-line-number="4"> fmap _ <span class="dt">Leaf</span> <span class="fu">=</span> <span class="dt">Leaf</span></a>
|
||
<a class="sourceLine" id="cb187-5" data-line-number="5"> fmap f (<span class="dt">Node</span> val left right) <span class="fu">=</span> <span class="dt">Node</span> (f val) (fmap f left) (fmap f right)</a></code></pre></div>
|
||
<p>Sidenote: the term functor comes originally from a branch of mathematics called <a href="https://en.wikipedia.org/wiki/Category_theory">category theory</a>. However, to work with Haskell you don’t need to know any category theory. When you see functor, you can just think “something I can map over”, or perhaps “a container”.</p>
|
||
<p>Let’s zoom out a bit. When we have an instance <code>Functor MyFun</code> we know that we can map a type <code>X</code> into a new type <code>MyFun X</code> (since <code>MyFun</code> is a type constructor), but also that we can lift a function <code>f</code> that takes an <code>X</code> argument into a function <code>fmap f</code> that takes a <code>MyFun X</code> argument! So you could say we’re mapping both on the type level and the value level.</p>
|
||
<p>Oh right, one more thing. Once you’ve gotten the hang of <code>fmap</code> you might find yourself using it quite a bit. For code that uses <code>fmap</code> heavily it can be nice to use its infix alias, <code><$></code>. Consider the symmetry between <code>$</code> and <code><$></code> in these examples:</p>
|
||
<div class="sourceCode" id="cb188"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb188-1" data-line-number="1">(<span class="fu">+</span><span class="dv">1</span>) <span class="fu"><$></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb188-2" data-line-number="2">not <span class="fu"><$></span> <span class="dt">Just</span> <span class="dt">False</span> <span class="fu">==></span> <span class="dt">Just</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb188-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb188-4" data-line-number="4">reverse <span class="fu">.</span> tail <span class="fu">$</span> <span class="st">"hello"</span> <span class="fu">==></span> <span class="st">"olle"</span></a>
|
||
<a class="sourceLine" id="cb188-5" data-line-number="5">reverse <span class="fu">.</span> tail <span class="fu"><$></span> <span class="dt">Just</span> <span class="st">"hello"</span> <span class="fu">==></span> <span class="dt">Just</span> <span class="st">"olle"</span></a>
|
||
<a class="sourceLine" id="cb188-6" data-line-number="6"><span class="co">-- which is the same as</span></a>
|
||
<a class="sourceLine" id="cb188-7" data-line-number="7">fmap (reverse <span class="fu">.</span> tail) (<span class="dt">Just</span> <span class="st">"hello"</span>) <span class="fu">==></span> <span class="dt">Just</span> <span class="st">"olle"</span></a></code></pre></div>
|
||
<h2 id="lawful-instances"><span class="header-section-number">12.3</span> Lawful Instances</h2>
|
||
<p>What is this “preserving of the structure” that was mentioned above exactly? The following two <em>functor laws</em> are expected to hold for any <code>Functor</code> instance <code>f</code> (though unfortunately Haskell compilers can’t enforce them):</p>
|
||
<ol type="1">
|
||
<li><code>fmap id === id</code></li>
|
||
<li><code>fmap (f . g) === fmap f . fmap g</code></li>
|
||
</ol>
|
||
<p>Don’t worry if that sounded abstract! The first law says that a functor maps <code>id :: a -> a</code> into <code>id :: f a -> f a</code>. (<code>id</code> is the identity function, meaning that <code>id x = x</code>.) Let’s be concrete and see how it works for the list <code>[1,2,3]</code>:</p>
|
||
<div class="sourceCode" id="cb189"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb189-1" data-line-number="1">fmap id [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> map id [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb189-2" data-line-number="2"> <span class="fu">==></span> map id (<span class="dv">1</span><span class="fu">:</span>[<span class="dv">2</span>,<span class="dv">3</span>])</a>
|
||
<a class="sourceLine" id="cb189-3" data-line-number="3"> <span class="fu">==></span> id <span class="dv">1</span> <span class="fu">:</span> map id [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb189-4" data-line-number="4"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">:</span> map id [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb189-5" data-line-number="5"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">:</span> id <span class="dv">2</span> <span class="fu">:</span> map id [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb189-6" data-line-number="6"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">:</span> <span class="dv">2</span> <span class="fu">:</span> id <span class="dv">3</span> <span class="fu">:</span> map id []</a>
|
||
<a class="sourceLine" id="cb189-7" data-line-number="7"> <span class="fu">==></span> <span class="dv">1</span> <span class="fu">:</span> <span class="dv">2</span> <span class="fu">:</span> <span class="dv">3</span> <span class="fu">:</span> []</a>
|
||
<a class="sourceLine" id="cb189-8" data-line-number="8"> <span class="fu">===</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<p>On the other hand,</p>
|
||
<div class="sourceCode" id="cb190"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb190-1" data-line-number="1">id [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<p>Hence, the result of <code>fmap id [1,2,3]</code> was the same as the result of <code>id [1,2,3]</code>, so the first functor law holds in this case. It’s not hard to show that the first functor law holds for any list whatsoever.</p>
|
||
<p>The first functor law is really a very simple proposition if you think about it. It just says that you can either <code>fmap id</code> or just apply <code>id</code> directly without a noticeable difference.</p>
|
||
<p>How about the second functor law? For lists, consider what happens if we <code>fmap</code> the function <code>negate.(*2)</code> (remember, <code>negate</code> maps <code>x</code> to <code>-x</code> and <code>(*2)</code> multiplies its argument by <code>2</code>):</p>
|
||
<div class="sourceCode" id="cb191"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb191-1" data-line-number="1">fmap (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-2" data-line-number="2"> <span class="fu">==></span> (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) <span class="dv">1</span> <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-3" data-line-number="3"> <span class="fu">==></span> negate (<span class="dv">1</span> <span class="fu">*</span> <span class="dv">2</span>) <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-4" data-line-number="4"> <span class="fu">==></span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-5" data-line-number="5"> <span class="fu">==></span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">:</span> (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) <span class="dv">2</span> <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-6" data-line-number="6"> <span class="fu">==></span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">:</span> <span class="fu">-</span><span class="dv">4</span> <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb191-7" data-line-number="7"> <span class="fu">==></span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">:</span> <span class="fu">-</span><span class="dv">4</span> <span class="fu">:</span> (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) <span class="dv">3</span> <span class="fu">:</span> map (negate<span class="fu">.</span>(<span class="fu">*</span><span class="dv">2</span>)) []</a>
|
||
<a class="sourceLine" id="cb191-8" data-line-number="8"> <span class="fu">==></span> <span class="fu">-</span><span class="dv">2</span> <span class="fu">:</span> <span class="fu">-</span><span class="dv">4</span> <span class="fu">:</span> <span class="fu">-</span><span class="dv">6</span> <span class="fu">:</span> []</a>
|
||
<a class="sourceLine" id="cb191-9" data-line-number="9"> <span class="fu">==></span> [<span class="fu">-</span><span class="dv">2</span>,<span class="fu">-</span><span class="dv">4</span>,<span class="fu">-</span><span class="dv">6</span>]</a></code></pre></div>
|
||
<p>Let’s consider the right-hand side of the second functor law in this case:</p>
|
||
<div class="sourceCode" id="cb192"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb192-1" data-line-number="1">(fmap negate <span class="fu">.</span> fmap (<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> (map negate <span class="fu">.</span> map (<span class="fu">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb192-2" data-line-number="2"> <span class="fu">==></span> map negate (map (<span class="fu">*</span><span class="dv">2</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])</a>
|
||
<a class="sourceLine" id="cb192-3" data-line-number="3"> <span class="fu">==></span> map negate [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</a>
|
||
<a class="sourceLine" id="cb192-4" data-line-number="4"> <span class="fu">==></span> [<span class="fu">-</span><span class="dv">2</span>,<span class="fu">-</span><span class="dv">4</span>,<span class="fu">-</span><span class="dv">6</span>]</a></code></pre></div>
|
||
<p>The second functor law turns out to hold in this particular case. In fact, it holds in all cases (exercise!). <!-- I used function extensionality (eta-conversion) for the functor laws
|
||
implicitly...--></p>
|
||
<h2 id="sidenote-kinds"><span class="header-section-number">12.4</span> Sidenote: Kinds</h2>
|
||
<p>Remember that <code>Functor</code> was a class for type constructors. If we try to define an instance of <code>Functor</code> for a type, we get an error:</p>
|
||
<div class="sourceCode" id="cb193"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb193-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Int</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb193-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb193-3" data-line-number="3"><span class="fu"><</span>interactive<span class="fu">>:</span><span class="dv">1</span><span class="fu">:</span><span class="dv">18</span><span class="fu">:</span> error<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb193-4" data-line-number="4"> • <span class="dt">Expected</span> kind ‘<span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span>’, but ‘<span class="dt">Int</span>’ has kind ‘<span class="fu">*</span>’</a>
|
||
<a class="sourceLine" id="cb193-5" data-line-number="5"> • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘<span class="dt">Functor</span>’, namely ‘<span class="dt">Int</span>’</a>
|
||
<a class="sourceLine" id="cb193-6" data-line-number="6"> <span class="dt">In</span> the <span class="kw">instance</span> declaration for ‘<span class="dt">Functor</span> <span class="dt">Int</span>’</a></code></pre></div>
|
||
<p>The error message talks about <em>kinds</em>. Kinds are <em>types of types</em>. A type like <code>Int</code>, <code>Bool</code> or <code>Maybe Int</code> that can contain values has kind <code>*</code>. A type constructor has a kind that looks like a function, for example, <code>Maybe</code> has kind <code>* -> *</code>. This means that the <code>Maybe</code> type constructor must be applied to a type of kind <code>*</code> to get a type of kind <code>*</code>.</p>
|
||
<p>We can ask GHCi for the kinds of types:</p>
|
||
<div class="sourceCode" id="cb194"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb194-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb194-2" data-line-number="2"><span class="dt">Int</span><span class="ot"> ::</span> <span class="fu">*</span></a>
|
||
<a class="sourceLine" id="cb194-3" data-line-number="3"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">Maybe</span></a>
|
||
<a class="sourceLine" id="cb194-4" data-line-number="4"><span class="dt">Maybe</span><span class="ot"> ::</span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span></a>
|
||
<a class="sourceLine" id="cb194-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">Maybe</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb194-6" data-line-number="6"><span class="dt">Maybe</span> <span class="dt">Int</span><span class="ot"> ::</span> <span class="fu">*</span></a></code></pre></div>
|
||
<p>If we ask GHCi for info about the <code>Functor</code> class, it tells us that instances of <code>Functor</code> must have kind <code>* -> *</code>:</p>
|
||
<div class="sourceCode" id="cb195"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb195-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>info <span class="dt">Functor</span></a>
|
||
<a class="sourceLine" id="cb195-2" data-line-number="2"><span class="kw">class</span> <span class="dt">Functor</span> (<span class="ot">f ::</span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span>) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb195-3" data-line-number="3"><span class="ot"> fmap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</a>
|
||
<a class="sourceLine" id="cb195-4" data-line-number="4"><span class="fu">...</span></a></code></pre></div>
|
||
<p>Here are some examples of even more complex kinds.</p>
|
||
<div class="sourceCode" id="cb196"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb196-1" data-line-number="1"><span class="co">-- multiple type parameters</span></a>
|
||
<a class="sourceLine" id="cb196-2" data-line-number="2"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">Either</span></a>
|
||
<a class="sourceLine" id="cb196-3" data-line-number="3"><span class="dt">Either</span><span class="ot"> ::</span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span></a>
|
||
<a class="sourceLine" id="cb196-4" data-line-number="4"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">data</span> <span class="dt">Either3</span> a b c <span class="fu">=</span> <span class="dt">Left</span> a <span class="fu">|</span> <span class="dt">Middle</span> b <span class="fu">|</span> <span class="dt">Right</span> c</a>
|
||
<a class="sourceLine" id="cb196-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">Either3</span></a>
|
||
<a class="sourceLine" id="cb196-6" data-line-number="6"><span class="dt">Either3</span><span class="ot"> ::</span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span></a>
|
||
<a class="sourceLine" id="cb196-7" data-line-number="7"><span class="co">-- a type parameter of kind *->*</span></a>
|
||
<a class="sourceLine" id="cb196-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">data</span> <span class="dt">IntInside</span> f <span class="fu">=</span> <span class="dt">IntInside</span> (f <span class="dt">Int</span>)</a>
|
||
<a class="sourceLine" id="cb196-9" data-line-number="9"><span class="dt">Prelude</span><span class="fu">></span> <span class="fu">:</span>kind <span class="dt">IntInside</span></a>
|
||
<a class="sourceLine" id="cb196-10" data-line-number="10"><span class="dt">IntInside</span><span class="ot"> ::</span> (<span class="fu">*</span> <span class="ot">-></span> <span class="fu">*</span>) <span class="ot">-></span> <span class="fu">*</span></a></code></pre></div>
|
||
<p>You won’t bump into kinds that much in Haskell programming, but sometimes you’ll see error messages that talk about kinds, so it’s good to know what they are.</p>
|
||
<h2 id="foldable-again"><span class="header-section-number">12.5</span> <code>Foldable</code>, Again</h2>
|
||
<p>We briefly covered the class <code>Foldable</code>, which occurs in many type signatures of basic functions, in part 1. For example:</p>
|
||
<div class="sourceCode" id="cb197"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb197-1" data-line-number="1">length<span class="ot"> ::</span> <span class="dt">Foldable</span> t <span class="ot">=></span> t a <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb197-2" data-line-number="2">sum<span class="ot"> ::</span> (<span class="dt">Foldable</span> t, <span class="dt">Num</span> a) <span class="ot">=></span> t a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb197-3" data-line-number="3">minimum<span class="ot"> ::</span> (<span class="dt">Foldable</span> t, <span class="dt">Ord</span> a) <span class="ot">=></span> t a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb197-4" data-line-number="4">foldMap<span class="ot"> ::</span> (<span class="dt">Foldable</span> t, <span class="dt">Monoid</span> m) <span class="ot">=></span> (a <span class="ot">-></span> m) <span class="ot">-></span> t a <span class="ot">-></span> m</a></code></pre></div>
|
||
<p>From these type signatures we can see that <code>Foldable</code>, just like <code>Functor</code>, is a class for type constructors (things of kind <code>* -> *</code>). The essence of <code>Foldable</code> is to be a class for <em>things you can fold over</em>. The class definition could be as simple as</p>
|
||
<div class="sourceCode" id="cb198"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb198-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Foldable</span> (<span class="ot">t ::</span> <span class="fu">*->*</span>) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb198-2" data-line-number="2"><span class="ot"> foldr ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> b) <span class="ot">-></span> b <span class="ot">-></span> t a <span class="ot">-></span> b</a></code></pre></div>
|
||
<p>However, for performance reasons, the class contains many methods (you can see them yourself by checking <code>:info Foldable</code> in GHCi!), but when we’re defining an instance for <code>Foldable</code> it’s enought to define just <code>foldr</code>.</p>
|
||
<p>Another way of thinking of the <code>Foldable</code> class is processing elements <em>left-to-right</em>, in other words, if <code>Functor</code> was the class for containers, <code>Foldable</code> is the class for <em>ordered containers</em>.</p>
|
||
<p>As an example, let’s implement <code>Functor</code> and <code>Foldable</code> for our own pair type.</p>
|
||
<div class="sourceCode" id="cb199"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb199-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Pair</span> a <span class="fu">=</span> <span class="dt">Pair</span> a a</a>
|
||
<a class="sourceLine" id="cb199-2" data-line-number="2"> <span class="kw">deriving</span> <span class="dt">Show</span></a>
|
||
<a class="sourceLine" id="cb199-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb199-4" data-line-number="4"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Pair</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb199-5" data-line-number="5"> <span class="co">-- fmap f applies f to all values</span></a>
|
||
<a class="sourceLine" id="cb199-6" data-line-number="6"> fmap f (<span class="dt">Pair</span> x y) <span class="fu">=</span> <span class="dt">Pair</span> (f x) (f y)</a>
|
||
<a class="sourceLine" id="cb199-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb199-8" data-line-number="8"><span class="kw">instance</span> <span class="dt">Foldable</span> <span class="dt">Pair</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb199-9" data-line-number="9"> <span class="co">-- just like applying foldr over a list of length 2</span></a>
|
||
<a class="sourceLine" id="cb199-10" data-line-number="10"> foldr f initialValue (<span class="dt">Pair</span> x y) <span class="fu">=</span> f x (f y initialValue)</a>
|
||
<a class="sourceLine" id="cb199-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb199-12" data-line-number="12"><span class="co">-- an example function that uses both instances</span></a>
|
||
<a class="sourceLine" id="cb199-13" data-line-number="13"><span class="ot">doubleAndCount ::</span> (<span class="dt">Functor</span> f, <span class="dt">Foldable</span> f) <span class="ot">=></span> f <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb199-14" data-line-number="14">doubleAndCount <span class="fu">=</span> sum <span class="fu">.</span> fmap (<span class="fu">*</span><span class="dv">2</span>)</a></code></pre></div>
|
||
<p>Now, we can use <code>Pair</code> almost wherever we can use a list:</p>
|
||
<div class="sourceCode" id="cb200"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb200-1" data-line-number="1">fmap (<span class="fu">+</span><span class="dv">1</span>) (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="fu">==></span> <span class="dt">Pair</span> <span class="dv">4</span> <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb200-2" data-line-number="2">fmap (<span class="fu">+</span><span class="dv">1</span>) [<span class="dv">3</span>,<span class="dv">6</span>] <span class="fu">==></span> [<span class="dv">4</span>,<span class="dv">7</span>]</a>
|
||
<a class="sourceLine" id="cb200-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb200-4" data-line-number="4">foldr (<span class="fu">*</span>) <span class="dv">1</span> (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="fu">==></span> <span class="dv">18</span></a>
|
||
<a class="sourceLine" id="cb200-5" data-line-number="5">foldr (<span class="fu">*</span>) <span class="dv">1</span> [<span class="dv">3</span>,<span class="dv">6</span>] <span class="fu">==></span> <span class="dv">18</span></a>
|
||
<a class="sourceLine" id="cb200-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb200-7" data-line-number="7">length (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="fu">==></span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb200-8" data-line-number="8">length [<span class="dv">3</span>,<span class="dv">6</span>] <span class="fu">==></span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb200-9" data-line-number="9"></a>
|
||
<a class="sourceLine" id="cb200-10" data-line-number="10">minimum (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="fu">==></span> <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb200-11" data-line-number="11">minimum [<span class="dv">3</span>,<span class="dv">6</span>] <span class="fu">==></span> <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb200-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb200-13" data-line-number="13">doubleAndCount (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="fu">==></span> <span class="dv">18</span></a>
|
||
<a class="sourceLine" id="cb200-14" data-line-number="14">doubleAndCount [<span class="dv">3</span>,<span class="dv">6</span>] <span class="fu">==></span> <span class="dv">18</span></a></code></pre></div>
|
||
<p>Other types we’ve met that are <code>Foldable</code> include <code>Data.Map</code> and <code>Data.Array</code>.</p>
|
||
<h2 id="recap"><span class="header-section-number">12.6</span> Recap</h2>
|
||
<p>So, to summarize, a functor is a type constructor <code>f</code> and the corresponding <code>Functor f</code> instance such that <code>fmap</code> satisfies the two functor laws. These laws assert that <code>fmap</code> must preserve the identity function and distribute over function composition. More informally, <code>fmap</code> lifts a function <code>g :: a -> b</code> operating on values to one operating on containers: <code>fmap g :: f a -> f b</code>. Basically all well-behaving data structures in Haskell are functors.</p>
|
||
<!-- ## TODO: something more? move some stuff from lecture 13 here -->
|
||
<h2 id="quiz-3"><span class="header-section-number">12.7</span> Quiz</h2>
|
||
<p>What’s the type of <code>fmap</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>a -> b -> f a -> f b</code>
|
||
</li>
|
||
<li>
|
||
<code>(a -> b) -> f a -> f b</code>
|
||
</li>
|
||
<li>
|
||
<code>Functor f => a -> b -> f a -> f b</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Functor f => (a -> b) -> f a -> f b</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which code snippet completes the next <code>Functor</code> instance?</p>
|
||
<div class="sourceCode" id="cb201"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb201-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Container</span> x <span class="fu">=</span> <span class="dt">Things</span> x [x]</a>
|
||
<a class="sourceLine" id="cb201-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb201-3" data-line-number="3"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Container</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb201-4" data-line-number="4"> <span class="fu">????</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>fmap f (Things x ys) = Things (f x) [f x]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>fmap f (Things x ys) = Things (f x) (map f ys)</code>
|
||
</li>
|
||
<li>
|
||
<code>fmap f (Things x ys) = Things (f x) ys</code>
|
||
</li>
|
||
<li>
|
||
<code>fmap f (Things x ys) = f (Things x ys)</code>
|
||
</li>
|
||
</ol>
|
||
<p>What’s the kind of <code>[a]</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>*</code>
|
||
</li>
|
||
<li>
|
||
<code>* -> *</code>
|
||
</li>
|
||
<li>
|
||
<code>[a]</code>
|
||
</li>
|
||
</ol>
|
||
<p>What’s the kind of <code>Foo</code>?</p>
|
||
<div class="sourceCode" id="cb202"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb202-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Foo</span> x <span class="fu">=</span> <span class="dt">FooConst</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>*</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>* -> *</code>
|
||
</li>
|
||
<li>
|
||
<code>Foo</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the value of <code>foldr (-) 1 (Just 2)</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
-1
|
||
</li>
|
||
<li class="correct">
|
||
1
|
||
</li>
|
||
<li>
|
||
<code>Just -1</code>
|
||
</li>
|
||
<li>
|
||
<code>Just 1</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which code snippet completes the next <code>Foldable</code> instance?</p>
|
||
<div class="sourceCode" id="cb203"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb203-1" data-line-number="1"><span class="kw">data</span> <span class="dt">Container</span> x <span class="fu">=</span> <span class="dt">Things</span> x [x]</a>
|
||
<a class="sourceLine" id="cb203-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb203-3" data-line-number="3"><span class="kw">instance</span> <span class="dt">Foldable</span> <span class="dt">Container</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb203-4" data-line-number="4"> <span class="fu">????</span></a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>foldr f z (Things x ys) = f x z</code>
|
||
</li>
|
||
<li>
|
||
<code>foldr f z (Things x ys) = foldr f x ys</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>foldr f z (Things x ys) = f x (foldr f z ys)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>foldr f z (Things x ys) = foldr f z (x:ys)</code>
|
||
</li>
|
||
</ol>
|
||
<h2 id="exercises-3"><span class="header-section-number">12.8</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set12.hs">Set12</a></li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
<h1 id="lecture-13-a-monoid-in-the-category-of-problems"><span class="header-section-number">13</span> Lecture 13: A Monoid in the Category of Problems</h1>
|
||
<ul>
|
||
<li>Monads</li>
|
||
</ul>
|
||
<p>In this lecture we’ll build up to the concept of a <em>monad</em> using a number of examples. By now you should be familiar with all the Haskell features needed for understanding monads.</p>
|
||
<p>Monads are a famously hard topic in programming, which is partly due to weird terminology, partly due to bad tutorials, and partly due to trying to understand monads too early when learning Haskell. Monads are introduced this late in the course in an attempt to make understanding them easier.</p>
|
||
<p>If you find this lecture hard, don’t despair, many others have found the topic hard as well. There are many many productive Haskell programmers who have managed to understand monads, so the task is not hopeless.</p>
|
||
<p>One final word of caution: monads, like functors, are a concept originally from a branch of mathematics called Category Theory. However, and I can’t stress this enough, <em>you do not need to know anything or even care about category theory to understand monads in Haskell programming.</em> Just like one can work with object-oriented programming or functional programming without knowing the theory of objects or functions, one can work with monads without understanding the math associated with them.</p>
|
||
<h2 id="example-1-maybes"><span class="header-section-number">13.1</span> Example 1: Maybes</h2>
|
||
<p>When working with many <code>Maybe</code> values, the code tends to become a bit messy. Let’s look at some examples. First, we combine some functions returning <code>Maybe String</code>. Note the nested <code>case</code> we need in <code>stealSecret</code>: not fun to write.</p>
|
||
<div class="sourceCode" id="cb204"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb204-1" data-line-number="1"><span class="co">-- Try to login with a password. `Just username` on success, `Nothing` otherwise.</span></a>
|
||
<a class="sourceLine" id="cb204-2" data-line-number="2"><span class="ot">login ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb204-3" data-line-number="3">login <span class="st">"f4bulous!"</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="st">"unicorn73"</span></a>
|
||
<a class="sourceLine" id="cb204-4" data-line-number="4">login <span class="st">"swordfish"</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="st">"megahacker"</span></a>
|
||
<a class="sourceLine" id="cb204-5" data-line-number="5">login _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb204-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb204-7" data-line-number="7"><span class="co">-- Get a secret associated with a user. Not all users have secrets.</span></a>
|
||
<a class="sourceLine" id="cb204-8" data-line-number="8"><span class="ot">secret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb204-9" data-line-number="9">secret <span class="st">"megahacker"</span> <span class="fu">=</span> <span class="dt">Just</span> <span class="st">"I like roses"</span></a>
|
||
<a class="sourceLine" id="cb204-10" data-line-number="10">secret _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb204-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb204-12" data-line-number="12"><span class="co">-- Login and return the user's secret, if any</span></a>
|
||
<a class="sourceLine" id="cb204-13" data-line-number="13"><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb204-14" data-line-number="14">stealSecret password <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb204-15" data-line-number="15"> <span class="kw">case</span> login password <span class="kw">of</span></a>
|
||
<a class="sourceLine" id="cb204-16" data-line-number="16"> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb204-17" data-line-number="17"> <span class="dt">Just</span> user <span class="ot">-></span> <span class="kw">case</span> secret user <span class="kw">of</span></a>
|
||
<a class="sourceLine" id="cb204-18" data-line-number="18"> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb204-19" data-line-number="19"> <span class="dt">Just</span> s <span class="ot">-></span> <span class="dt">Just</span> (<span class="st">"Stole secret: "</span><span class="fu">++</span>s)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb205"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb205-1" data-line-number="1">stealSecret <span class="st">"swordfish"</span> <span class="fu">==></span> <span class="dt">Just</span> <span class="st">"Stole secret: I like roses"</span></a>
|
||
<a class="sourceLine" id="cb205-2" data-line-number="2">stealSecret <span class="st">"f4bulous!"</span> <span class="fu">==></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb205-3" data-line-number="3">stealSecret <span class="st">"wrong_password"</span> <span class="fu">==></span> <span class="dt">Nothing</span></a></code></pre></div>
|
||
<p>Next up, we modify a list of pairs. We use the <code>Maybe</code>-returning function <code>lookup</code> from the Prelude. Here we have an if inside a case instead of a nested case.</p>
|
||
<div class="sourceCode" id="cb206"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb206-1" data-line-number="1"><span class="co">-- Get the value corresponding to a key from a key-value list.</span></a>
|
||
<a class="sourceLine" id="cb206-2" data-line-number="2">lookup<span class="ot"> ::</span> (<span class="dt">Eq</span> a) <span class="ot">=></span> a <span class="ot">-></span> [(a, b)] <span class="ot">-></span> <span class="dt">Maybe</span> b</a></code></pre></div>
|
||
<div class="sourceCode" id="cb207"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb207-1" data-line-number="1"><span class="co">-- Set the value of key to val in the given key-value list,</span></a>
|
||
<a class="sourceLine" id="cb207-2" data-line-number="2"><span class="co">-- but only if val is larger than the current value!</span></a>
|
||
<a class="sourceLine" id="cb207-3" data-line-number="3"><span class="ot">increase ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(a,<span class="dt">Int</span>)] <span class="ot">-></span> <span class="dt">Maybe</span> [(a,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb207-4" data-line-number="4">increase key val assocs <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb207-5" data-line-number="5"> <span class="kw">case</span> lookup key assocs</a>
|
||
<a class="sourceLine" id="cb207-6" data-line-number="6"> <span class="kw">of</span> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb207-7" data-line-number="7"> <span class="dt">Just</span> x <span class="ot">-></span> <span class="kw">if</span> (val <span class="fu"><</span> x)</a>
|
||
<a class="sourceLine" id="cb207-8" data-line-number="8"> <span class="kw">then</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb207-9" data-line-number="9"> <span class="kw">else</span> <span class="dt">Just</span> ((key,val) <span class="fu">:</span> delete (key,x) assocs)</a></code></pre></div>
|
||
<p>This type of code is pretty common, and usually repeats the same pattern: if any intermediate result is <code>Nothing</code>, the whole result is <code>Nothing</code>. Let’s try to make writing code like this easier by defining a <em>chaining operator</em> <code>?></code>. The chaining operator takes a result and the next step of computation, and only runs the next step if the result was a <code>Just</code> value.</p>
|
||
<div class="sourceCode" id="cb208"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb208-1" data-line-number="1"><span class="ot">(?>) ::</span> <span class="dt">Maybe</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">Maybe</span> b) <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb208-2" data-line-number="2"><span class="dt">Nothing</span> <span class="fu">?></span> _ <span class="fu">=</span> <span class="dt">Nothing</span> <span class="co">-- if we failed, don't even bother running the next step</span></a>
|
||
<a class="sourceLine" id="cb208-3" data-line-number="3"><span class="dt">Just</span> x <span class="fu">?></span> f <span class="fu">=</span> f x <span class="co">-- otherwise run the next step</span></a></code></pre></div>
|
||
<p>The chaining operator streamlines our examples nicely. Note how we can define simple helper functions that take care of one step of the computation instead of writing one big expression.</p>
|
||
<div class="sourceCode" id="cb209"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb209-1" data-line-number="1"><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb209-2" data-line-number="2">stealSecret password <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb209-3" data-line-number="3"> login password <span class="fu">?></span></a>
|
||
<a class="sourceLine" id="cb209-4" data-line-number="4"> secret <span class="fu">?></span></a>
|
||
<a class="sourceLine" id="cb209-5" data-line-number="5"> decorate</a>
|
||
<a class="sourceLine" id="cb209-6" data-line-number="6"> <span class="kw">where</span> decorate s <span class="fu">=</span> <span class="dt">Just</span> (<span class="st">"Stole secret: "</span><span class="fu">++</span>s)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb210"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb210-1" data-line-number="1"><span class="ot">increase ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(a,<span class="dt">Int</span>)] <span class="ot">-></span> <span class="dt">Maybe</span> [(a,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb210-2" data-line-number="2">increase key val assocs <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb210-3" data-line-number="3"> lookup key assocs <span class="fu">?></span></a>
|
||
<a class="sourceLine" id="cb210-4" data-line-number="4"> check <span class="fu">?></span></a>
|
||
<a class="sourceLine" id="cb210-5" data-line-number="5"> buildResult</a>
|
||
<a class="sourceLine" id="cb210-6" data-line-number="6"> <span class="kw">where</span> check x</a>
|
||
<a class="sourceLine" id="cb210-7" data-line-number="7"> <span class="fu">|</span> x <span class="fu"><</span> val <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb210-8" data-line-number="8"> <span class="fu">|</span> otherwise <span class="fu">=</span> <span class="dt">Just</span> x</a>
|
||
<a class="sourceLine" id="cb210-9" data-line-number="9"> buildResult x <span class="fu">=</span> <span class="dt">Just</span> ((key,val) <span class="fu">:</span> delete (key,x) assocs)</a></code></pre></div>
|
||
<p>Here’s another example: safe list indexing built from <code>safeHead</code> and <code>safeTail</code>:</p>
|
||
<div class="sourceCode" id="cb211"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb211-1" data-line-number="1"><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb211-2" data-line-number="2">safeHead [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb211-3" data-line-number="3">safeHead (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dt">Just</span> x</a>
|
||
<a class="sourceLine" id="cb211-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb211-5" data-line-number="5"><span class="ot">safeTail ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</a>
|
||
<a class="sourceLine" id="cb211-6" data-line-number="6">safeTail [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb211-7" data-line-number="7">safeTail (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dt">Just</span> xs</a>
|
||
<a class="sourceLine" id="cb211-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb211-9" data-line-number="9"><span class="ot">safeThird ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb211-10" data-line-number="10">safeThird xs <span class="fu">=</span> safeTail xs <span class="fu">?></span> safeTail <span class="fu">?></span> safeHead</a>
|
||
<a class="sourceLine" id="cb211-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb211-12" data-line-number="12"><span class="ot">safeNth ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb211-13" data-line-number="13">safeNth <span class="dv">0</span> xs <span class="fu">=</span> safeHead xs</a>
|
||
<a class="sourceLine" id="cb211-14" data-line-number="14">safeNth n xs <span class="fu">=</span> safeTail xs <span class="fu">?></span> safeNth (n<span class="fu">-</span><span class="dv">1</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb212"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb212-1" data-line-number="1">safeThird [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb212-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb212-3" data-line-number="3">safeThird [<span class="dv">1</span>,<span class="dv">2</span>]</a>
|
||
<a class="sourceLine" id="cb212-4" data-line-number="4"> <span class="fu">==></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb212-5" data-line-number="5">safeNth <span class="dv">5</span> [<span class="dv">1</span><span class="fu">..</span><span class="dv">10</span>]</a>
|
||
<a class="sourceLine" id="cb212-6" data-line-number="6"> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb212-7" data-line-number="7">safeNth <span class="dv">11</span> [<span class="dv">1</span><span class="fu">..</span><span class="dv">10</span>]</a>
|
||
<a class="sourceLine" id="cb212-8" data-line-number="8"> <span class="fu">==></span> <span class="dt">Nothing</span></a></code></pre></div>
|
||
<p>PS. note that <code>?></code> <em>associates to the left</em> as is the default in Haskell. That means that <code>op ?> f ?> g</code> means <code>(op ?> f) ?> g</code>. The alternative, <code>op ?> (f ?> g)</code> would not even type check!</p>
|
||
<p>Sidenote: this <code>?></code> operator expresses the if-result pattern that’s very common in other languages. Here is how one would write <code>op val ?> f</code> in Python and Java.</p>
|
||
<div class="sourceCode" id="cb213"><pre class="sourceCode python"><code class="sourceCode python"><a class="sourceLine" id="cb213-1" data-line-number="1"><span class="co"># Python</span></a>
|
||
<a class="sourceLine" id="cb213-2" data-line-number="2">x <span class="op">=</span> op(val)</a>
|
||
<a class="sourceLine" id="cb213-3" data-line-number="3"><span class="cf">if</span> x:</a>
|
||
<a class="sourceLine" id="cb213-4" data-line-number="4"> f x</a></code></pre></div>
|
||
<div class="sourceCode" id="cb214"><pre class="sourceCode java"><code class="sourceCode java"><a class="sourceLine" id="cb214-1" data-line-number="1"><span class="co">// Java</span></a>
|
||
<a class="sourceLine" id="cb214-2" data-line-number="2"><span class="bu">Object</span> x = <span class="fu">op</span>(val);</a>
|
||
<a class="sourceLine" id="cb214-3" data-line-number="3"><span class="kw">if</span> (x != <span class="kw">null</span>) {</a>
|
||
<a class="sourceLine" id="cb214-4" data-line-number="4"> <span class="fu">f</span>(x);</a>
|
||
<a class="sourceLine" id="cb214-5" data-line-number="5">}</a></code></pre></div>
|
||
<p>The difference between the if-result pattern and our <code>?></code> is that we use the <code>Nothing</code> value to explicitly signal failure, instead of relying on the fact that any variable can be <code>None</code> (or <code>False</code>) in Python, or that any <code>Object</code> reference can be <code>null</code> in Java.</p>
|
||
<h2 id="example-2-logging"><span class="header-section-number">13.2</span> Example 2: Logging</h2>
|
||
<p>Let’s explore the concept of chaining with another example: logging. The type <code>Logger</code> represents a value plus a list of log messages (produced by the computation that produced the value).</p>
|
||
<div class="sourceCode" id="cb215"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb215-1" data-line-number="1"><span class="co">-- Logger definition</span></a>
|
||
<a class="sourceLine" id="cb215-2" data-line-number="2"><span class="kw">data</span> <span class="dt">Logger</span> a <span class="fu">=</span> <span class="dt">Logger</span> [<span class="dt">String</span>] a <span class="kw">deriving</span> <span class="dt">Show</span></a>
|
||
<a class="sourceLine" id="cb215-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb215-4" data-line-number="4"><span class="ot">getVal ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> a</a>
|
||
<a class="sourceLine" id="cb215-5" data-line-number="5">getVal (<span class="dt">Logger</span> _ a) <span class="fu">=</span> a</a>
|
||
<a class="sourceLine" id="cb215-6" data-line-number="6"><span class="ot">getLog ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb215-7" data-line-number="7">getLog (<span class="dt">Logger</span> s _) <span class="fu">=</span> s</a>
|
||
<a class="sourceLine" id="cb215-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb215-9" data-line-number="9"><span class="co">-- Primitive operations:</span></a>
|
||
<a class="sourceLine" id="cb215-10" data-line-number="10"><span class="ot">nomsg ::</span> a <span class="ot">-></span> <span class="dt">Logger</span> a</a>
|
||
<a class="sourceLine" id="cb215-11" data-line-number="11">nomsg x <span class="fu">=</span> <span class="dt">Logger</span> [] x <span class="co">-- a value, no message</span></a>
|
||
<a class="sourceLine" id="cb215-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb215-13" data-line-number="13"><span class="ot">annotate ::</span> <span class="dt">String</span> <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Logger</span> a</a>
|
||
<a class="sourceLine" id="cb215-14" data-line-number="14">annotate s x <span class="fu">=</span> <span class="dt">Logger</span> [s] x <span class="co">-- a value and a message</span></a>
|
||
<a class="sourceLine" id="cb215-15" data-line-number="15"></a>
|
||
<a class="sourceLine" id="cb215-16" data-line-number="16"><span class="ot">msg ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> ()</a>
|
||
<a class="sourceLine" id="cb215-17" data-line-number="17">msg s <span class="fu">=</span> <span class="dt">Logger</span> [s] () <span class="co">-- just a message</span></a></code></pre></div>
|
||
<p>Here’s a <code>login</code> function that logs some details about the usernames and passwords it processes. Note how we run into complicated code in <code>login</code> when we need to handle multiple <code>Logger</code> values.</p>
|
||
<div class="sourceCode" id="cb216"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb216-1" data-line-number="1"><span class="ot">validateUser ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb216-2" data-line-number="2">validateUser <span class="st">"paul.atreides"</span> <span class="fu">=</span> annotate <span class="st">"Valid user"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb216-3" data-line-number="3">validateUser <span class="st">"ninja"</span> <span class="fu">=</span> nomsg <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb216-4" data-line-number="4">validateUser u <span class="fu">=</span> annotate (<span class="st">"Invalid user: "</span><span class="fu">++</span>u) <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb216-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb216-6" data-line-number="6"><span class="ot">checkPassword ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb216-7" data-line-number="7">checkPassword <span class="st">"paul.atreides"</span> <span class="st">"muad'dib"</span> <span class="fu">=</span> annotate <span class="st">"Password ok"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb216-8" data-line-number="8">checkPassword <span class="st">"ninja"</span> <span class="st">""</span> <span class="fu">=</span> annotate <span class="st">"Password ok"</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb216-9" data-line-number="9">checkPassword _ pass <span class="fu">=</span> annotate (<span class="st">"Password wrong: "</span><span class="fu">++</span>pass) <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb216-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb216-11" data-line-number="11"><span class="ot">login ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb216-12" data-line-number="12">login user password <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb216-13" data-line-number="13"> <span class="kw">let</span> validation <span class="fu">=</span> validateUser user</a>
|
||
<a class="sourceLine" id="cb216-14" data-line-number="14"> <span class="kw">in</span> <span class="kw">if</span> (getVal validation)</a>
|
||
<a class="sourceLine" id="cb216-15" data-line-number="15"> <span class="kw">then</span> <span class="kw">let</span> check <span class="fu">=</span> checkPassword user password</a>
|
||
<a class="sourceLine" id="cb216-16" data-line-number="16"> <span class="kw">in</span> <span class="dt">Logger</span> (getLog validation <span class="fu">++</span> getLog check) (getVal check)</a>
|
||
<a class="sourceLine" id="cb216-17" data-line-number="17"> <span class="kw">else</span> validation</a></code></pre></div>
|
||
<div class="sourceCode" id="cb217"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb217-1" data-line-number="1">login <span class="st">"paul.atreides"</span> <span class="st">"muad'dib"</span></a>
|
||
<a class="sourceLine" id="cb217-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"Valid user"</span>,<span class="st">"Password ok"</span>] <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb217-3" data-line-number="3">login <span class="st">"paul.atreides"</span> <span class="st">"arrakis"</span></a>
|
||
<a class="sourceLine" id="cb217-4" data-line-number="4"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"Valid user"</span>,<span class="st">"Password wrong: arrakis"</span>] <span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb217-5" data-line-number="5">login <span class="st">"ninja"</span> <span class="st">""</span></a>
|
||
<a class="sourceLine" id="cb217-6" data-line-number="6"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"Password ok"</span>] <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb217-7" data-line-number="7">login <span class="st">"leto.atreides"</span> <span class="st">"paul"</span></a>
|
||
<a class="sourceLine" id="cb217-8" data-line-number="8"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"Invalid user: leto.atreides"</span>] <span class="dt">False</span></a></code></pre></div>
|
||
<p>Let’s try to streamline this code by defining a chaining operator for <code>Logger</code>. The important thing when doing multiple <code>Logger</code> operations is to preserve all the logs. Here’s a chaining operator, <code>#></code>, and an example of how it can be used to log some arithmetic computations.</p>
|
||
<div class="sourceCode" id="cb218"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb218-1" data-line-number="1"><span class="ot">(#>) ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">Logger</span> b) <span class="ot">-></span> <span class="dt">Logger</span> b</a>
|
||
<a class="sourceLine" id="cb218-2" data-line-number="2"><span class="dt">Logger</span> la a <span class="fu">#></span> f <span class="fu">=</span> <span class="kw">let</span> <span class="dt">Logger</span> lb b <span class="fu">=</span> f a <span class="co">-- feed value to next step</span></a>
|
||
<a class="sourceLine" id="cb218-3" data-line-number="3"> <span class="kw">in</span> <span class="dt">Logger</span> (la<span class="fu">++</span>lb) b <span class="co">-- bundle result with all messages</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb219"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb219-1" data-line-number="1"><span class="co">-- square a number and log a message about it</span></a>
|
||
<a class="sourceLine" id="cb219-2" data-line-number="2"><span class="ot">square ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb219-3" data-line-number="3">square val <span class="fu">=</span> annotate (show val <span class="fu">++</span> <span class="st">"^2"</span>) (val<span class="fu">^</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb219-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb219-5" data-line-number="5"><span class="co">-- add 1 to a number and log a message about it</span></a>
|
||
<a class="sourceLine" id="cb219-6" data-line-number="6"><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb219-7" data-line-number="7">add val <span class="fu">=</span> annotate (show val <span class="fu">++</span> <span class="st">"+1"</span>) (val<span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb219-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb219-9" data-line-number="9"><span class="co">-- double a number and log a message about it</span></a>
|
||
<a class="sourceLine" id="cb219-10" data-line-number="10"><span class="ot">double ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb219-11" data-line-number="11">double val <span class="fu">=</span> annotate (show val <span class="fu">++</span> <span class="st">"*2"</span>) (val<span class="fu">*</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb219-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb219-13" data-line-number="13"><span class="co">-- compute the expression 2*(x^2+1) with logging</span></a>
|
||
<a class="sourceLine" id="cb219-14" data-line-number="14"><span class="ot">compute ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb219-15" data-line-number="15">compute x <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb219-16" data-line-number="16"> square x</a>
|
||
<a class="sourceLine" id="cb219-17" data-line-number="17"> <span class="fu">#></span> add</a>
|
||
<a class="sourceLine" id="cb219-18" data-line-number="18"> <span class="fu">#></span> double</a></code></pre></div>
|
||
<div class="sourceCode" id="cb220"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb220-1" data-line-number="1">compute <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb220-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"3^2"</span>,<span class="st">"9+1"</span>,<span class="st">"10*2"</span>] <span class="dv">20</span></a></code></pre></div>
|
||
<p>We can streamline <code>login</code> quite a bit by using <code>#></code>. Note how we don’t need to worry about combining logs together. Also note how we use a lambda expression instead of defining a helper function.</p>
|
||
<div class="sourceCode" id="cb221"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb221-1" data-line-number="1"><span class="ot">login ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb221-2" data-line-number="2">login user password <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb221-3" data-line-number="3"> validateUser user</a>
|
||
<a class="sourceLine" id="cb221-4" data-line-number="4"> <span class="fu">#></span></a>
|
||
<a class="sourceLine" id="cb221-5" data-line-number="5"> \valid <span class="ot">-></span> <span class="kw">if</span> valid <span class="kw">then</span> checkPassword user password</a>
|
||
<a class="sourceLine" id="cb221-6" data-line-number="6"> <span class="kw">else</span> nomsg <span class="dt">False</span></a></code></pre></div>
|
||
<p>To ramp things up a bit, let’s use <code>Logger</code> in a recursive list processing function. Here’s a logging version of <code>filter</code>. Note how the code chains a log message before the recursive call in order to keep the order of log entries nice.</p>
|
||
<div class="sourceCode" id="cb222"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb222-1" data-line-number="1"><span class="co">-- sometimes you don't need the previous value:</span></a>
|
||
<a class="sourceLine" id="cb222-2" data-line-number="2"><span class="ot">(##>) ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> <span class="dt">Logger</span> b <span class="ot">-></span> <span class="dt">Logger</span> b</a>
|
||
<a class="sourceLine" id="cb222-3" data-line-number="3"><span class="dt">Logger</span> la _ <span class="fu">##></span> <span class="dt">Logger</span> lb b <span class="fu">=</span> <span class="dt">Logger</span> (la<span class="fu">++</span>lb) b</a>
|
||
<a class="sourceLine" id="cb222-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb222-5" data-line-number="5"><span class="ot">filterLog ::</span> (<span class="dt">Eq</span> a, <span class="dt">Show</span> a) <span class="ot">=></span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Logger</span> [a]</a>
|
||
<a class="sourceLine" id="cb222-6" data-line-number="6">filterLog f [] <span class="fu">=</span> nomsg []</a>
|
||
<a class="sourceLine" id="cb222-7" data-line-number="7">filterLog f (x<span class="fu">:</span>xs)</a>
|
||
<a class="sourceLine" id="cb222-8" data-line-number="8"> <span class="fu">|</span> f x <span class="fu">=</span> msg (<span class="st">"keeping "</span><span class="fu">++</span>show x) <span class="fu">##></span> filterLog f xs <span class="fu">#></span> (\xs' <span class="ot">-></span> nomsg (x<span class="fu">:</span>xs'))</a>
|
||
<a class="sourceLine" id="cb222-9" data-line-number="9"> <span class="fu">|</span> otherwise <span class="fu">=</span> msg (<span class="st">"dropping "</span><span class="fu">++</span>show x) <span class="fu">##></span> filterLog f xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb223"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb223-1" data-line-number="1">filterLog (<span class="fu">></span><span class="dv">0</span>) [<span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>,<span class="dv">0</span>]</a>
|
||
<a class="sourceLine" id="cb223-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"keeping 1"</span>,<span class="st">"dropping -2"</span>,<span class="st">"keeping 3"</span>,<span class="st">"dropping -4"</span>,<span class="st">"dropping 0"</span>] [<span class="dv">1</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<h2 id="example-3-keeping-state"><span class="header-section-number">13.3</span> Example 3: Keeping State</h2>
|
||
<p>In the previous example we just wrote some state (the log). Sometimes we need computations that change some sort of shared state. Let’s look at accounts in a small bank. We’ll first define a datatype for the state of the bank: the balances of all accounts, as a map from account name to balance.</p>
|
||
<div class="sourceCode" id="cb224"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb224-1" data-line-number="1"><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">Map</span></a>
|
||
<a class="sourceLine" id="cb224-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb224-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Bank</span> <span class="fu">=</span> <span class="dt">Bank</span> (<span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span>)</a>
|
||
<a class="sourceLine" id="cb224-4" data-line-number="4"> <span class="kw">deriving</span> <span class="dt">Show</span></a></code></pre></div>
|
||
<p>Here’s how we can deposit some money to an account. We use the function <code>adjust</code> from <code>Data.Map</code> to modify the map.</p>
|
||
<div class="sourceCode" id="cb225"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb225-1" data-line-number="1"><span class="co">-- Apply a function to one value in a map</span></a>
|
||
<a class="sourceLine" id="cb225-2" data-line-number="2">Map.adjust<span class="ot"> ::</span> <span class="dt">Ord</span> k <span class="ot">=></span> (a <span class="ot">-></span> a) <span class="ot">-></span> k <span class="ot">-></span> <span class="dt">Map.Map</span> k a <span class="ot">-></span> <span class="dt">Map.Map</span> k a</a></code></pre></div>
|
||
<div class="sourceCode" id="cb226"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb226-1" data-line-number="1"><span class="ot">deposit ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> <span class="dt">Bank</span></a>
|
||
<a class="sourceLine" id="cb226-2" data-line-number="2">deposit accountName amount (<span class="dt">Bank</span> accounts) <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb226-3" data-line-number="3"> <span class="dt">Bank</span> (Map.adjust (\x <span class="ot">-></span> x<span class="fu">+</span>amount) accountName accounts)</a></code></pre></div>
|
||
<p>Withdrawing money is a bit more complicated, since we want to handle some special cases like the account not existing, or the account not having enough money. We use the library function <code>findWithDefault</code> to help us along.</p>
|
||
<div class="sourceCode" id="cb227"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb227-1" data-line-number="1"><span class="co">-- Fetch the value corresponding to a key from a map, or a default value</span></a>
|
||
<a class="sourceLine" id="cb227-2" data-line-number="2"><span class="co">-- in case the key does not exist</span></a>
|
||
<a class="sourceLine" id="cb227-3" data-line-number="3">Map.findWithDefault<span class="ot"> ::</span> <span class="dt">Ord</span> k <span class="ot">=></span> a <span class="ot">-></span> k <span class="ot">-></span> <span class="dt">Map.Map</span> k a <span class="ot">-></span> a</a></code></pre></div>
|
||
<div class="sourceCode" id="cb228"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb228-1" data-line-number="1"><span class="ot">withdraw ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> (<span class="dt">Int</span>,<span class="dt">Bank</span>)</a>
|
||
<a class="sourceLine" id="cb228-2" data-line-number="2">withdraw accountName amount (<span class="dt">Bank</span> accounts) <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb228-3" data-line-number="3"> <span class="kw">let</span> balance <span class="fu">=</span> Map.findWithDefault <span class="dv">0</span> accountName accounts <span class="co">-- balance is 0 for a nonexistant account</span></a>
|
||
<a class="sourceLine" id="cb228-4" data-line-number="4"> withdrawal <span class="fu">=</span> min amount balance <span class="co">-- can't withdraw over balance</span></a>
|
||
<a class="sourceLine" id="cb228-5" data-line-number="5"> newAccounts <span class="fu">=</span> Map.adjust (\x <span class="ot">-></span> x<span class="fu">-</span>withdrawal) accountName accounts</a>
|
||
<a class="sourceLine" id="cb228-6" data-line-number="6"> <span class="kw">in</span> (withdrawal, <span class="dt">Bank</span> newAccounts)</a></code></pre></div>
|
||
<p>Finally, let’s write a function that takes at most 100 money from one account, splits the money in half, and deposits it in two accounts. Pay attention to how we need to carefully thread the different versions of the bank, <code>bank</code>, <code>bank1</code>, <code>bank2</code> and <code>bank3</code> to make sure all transactions happen in the right order.</p>
|
||
<div class="sourceCode" id="cb229"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb229-1" data-line-number="1"><span class="ot">share ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> <span class="dt">Bank</span></a>
|
||
<a class="sourceLine" id="cb229-2" data-line-number="2">share from to1 to2 bank <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb229-3" data-line-number="3"> <span class="kw">let</span> (amount,bank1) <span class="fu">=</span> withdraw from <span class="dv">100</span> bank</a>
|
||
<a class="sourceLine" id="cb229-4" data-line-number="4"> half <span class="fu">=</span> div amount <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb229-5" data-line-number="5"> rest <span class="fu">=</span> amount<span class="fu">-</span>half <span class="co">-- carefully preserve all money, even if amount was an odd number</span></a>
|
||
<a class="sourceLine" id="cb229-6" data-line-number="6"> bank2 <span class="fu">=</span> deposit to1 half bank1</a>
|
||
<a class="sourceLine" id="cb229-7" data-line-number="7"> bank3 <span class="fu">=</span> deposit to2 rest bank2</a>
|
||
<a class="sourceLine" id="cb229-8" data-line-number="8"> <span class="kw">in</span> bank3</a></code></pre></div>
|
||
<div class="sourceCode" id="cb230"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb230-1" data-line-number="1">share <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span></a>
|
||
<a class="sourceLine" id="cb230-2" data-line-number="2"> (<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">0</span>),(<span class="st">"siegfried"</span>,<span class="dv">0</span>),(<span class="st">"wotan"</span>,<span class="dv">1000</span>)]))</a>
|
||
<a class="sourceLine" id="cb230-3" data-line-number="3"> <span class="fu">==></span> <span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">50</span>),(<span class="st">"siegfried"</span>,<span class="dv">50</span>),(<span class="st">"wotan"</span>,<span class="dv">900</span>)])</a>
|
||
<a class="sourceLine" id="cb230-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb230-5" data-line-number="5">share <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span></a>
|
||
<a class="sourceLine" id="cb230-6" data-line-number="6"> (<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">0</span>),(<span class="st">"siegfried"</span>,<span class="dv">0</span>),(<span class="st">"wotan"</span>,<span class="dv">91</span>)]))</a>
|
||
<a class="sourceLine" id="cb230-7" data-line-number="7"> <span class="fu">==></span> <span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">46</span>),(<span class="st">"siegfried"</span>,<span class="dv">45</span>),(<span class="st">"wotan"</span>,<span class="dv">0</span>)])</a></code></pre></div>
|
||
<p>Code like this turns up often in Haskell when you’re doing serial updates to one value, while also performing some other computations on the side. It’s easy to make a mistake, and the type system won’t help you if you e.g. reuse the <code>bank1</code> value. Let’s rewrite <code>share</code> so that we don’t need to refer to the bank itself. We can again use the same chaining idea to accomplish this.</p>
|
||
<div class="sourceCode" id="cb231"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb231-1" data-line-number="1"><span class="co">-- `BankOp a` is an operation that transforms a Bank value, while returning a value of type `a`</span></a>
|
||
<a class="sourceLine" id="cb231-2" data-line-number="2"><span class="kw">data</span> <span class="dt">BankOp</span> a <span class="fu">=</span> <span class="dt">BankOp</span> (<span class="dt">Bank</span> <span class="ot">-></span> (a,<span class="dt">Bank</span>))</a>
|
||
<a class="sourceLine" id="cb231-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb231-4" data-line-number="4"><span class="co">-- running a BankOp on a Bank</span></a>
|
||
<a class="sourceLine" id="cb231-5" data-line-number="5"><span class="ot">runBankOp ::</span> <span class="dt">BankOp</span> a <span class="ot">-></span> <span class="dt">Bank</span> <span class="ot">-></span> (a,<span class="dt">Bank</span>)</a>
|
||
<a class="sourceLine" id="cb231-6" data-line-number="6">runBankOp (<span class="dt">BankOp</span> f) bank <span class="fu">=</span> f bank</a>
|
||
<a class="sourceLine" id="cb231-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb231-8" data-line-number="8"><span class="co">-- Running one BankOp after another</span></a>
|
||
<a class="sourceLine" id="cb231-9" data-line-number="9"><span class="ot">(+>>) ::</span> <span class="dt">BankOp</span> a <span class="ot">-></span> <span class="dt">BankOp</span> b <span class="ot">-></span> <span class="dt">BankOp</span> b</a>
|
||
<a class="sourceLine" id="cb231-10" data-line-number="10">op1 <span class="fu">+>></span> op2 <span class="fu">=</span> <span class="dt">BankOp</span> combined</a>
|
||
<a class="sourceLine" id="cb231-11" data-line-number="11"> <span class="kw">where</span> combined bank <span class="fu">=</span> <span class="kw">let</span> (_,bank1) <span class="fu">=</span> runBankOp op1 bank</a>
|
||
<a class="sourceLine" id="cb231-12" data-line-number="12"> <span class="kw">in</span> runBankOp op2 bank1</a>
|
||
<a class="sourceLine" id="cb231-13" data-line-number="13"></a>
|
||
<a class="sourceLine" id="cb231-14" data-line-number="14"><span class="co">-- Running a parameterized BankOp, using the value returned by a previous BankOp</span></a>
|
||
<a class="sourceLine" id="cb231-15" data-line-number="15"><span class="co">-- The implementation is a bit tricky but it's enough to understand how +> is used for now.</span></a>
|
||
<a class="sourceLine" id="cb231-16" data-line-number="16"><span class="ot">(+>) ::</span> <span class="dt">BankOp</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">BankOp</span> b) <span class="ot">-></span> <span class="dt">BankOp</span> b</a>
|
||
<a class="sourceLine" id="cb231-17" data-line-number="17">op <span class="fu">+></span> parameterized <span class="fu">=</span> <span class="dt">BankOp</span> combined</a>
|
||
<a class="sourceLine" id="cb231-18" data-line-number="18"> <span class="kw">where</span> combined bank <span class="fu">=</span> <span class="kw">let</span> (a,bank1) <span class="fu">=</span> runBankOp op bank</a>
|
||
<a class="sourceLine" id="cb231-19" data-line-number="19"> <span class="kw">in</span> runBankOp (parameterized a) bank1</a>
|
||
<a class="sourceLine" id="cb231-20" data-line-number="20"></a>
|
||
<a class="sourceLine" id="cb231-21" data-line-number="21"><span class="co">-- Make a BankOp out of deposit. There is no return value so we use ().</span></a>
|
||
<a class="sourceLine" id="cb231-22" data-line-number="22"><span class="ot">depositOp ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">BankOp</span> ()</a>
|
||
<a class="sourceLine" id="cb231-23" data-line-number="23">depositOp accountName amount <span class="fu">=</span> <span class="dt">BankOp</span> depositHelper</a>
|
||
<a class="sourceLine" id="cb231-24" data-line-number="24"> <span class="kw">where</span> depositHelper bank <span class="fu">=</span> ((), deposit accountName amount bank)</a>
|
||
<a class="sourceLine" id="cb231-25" data-line-number="25"></a>
|
||
<a class="sourceLine" id="cb231-26" data-line-number="26"><span class="co">-- Make a BankOp out of withdraw. Note how</span></a>
|
||
<a class="sourceLine" id="cb231-27" data-line-number="27"><span class="co">-- withdraw accountName amount :: Bank -> (Int,Bank)</span></a>
|
||
<a class="sourceLine" id="cb231-28" data-line-number="28"><span class="co">-- is almost a BankOp already!</span></a>
|
||
<a class="sourceLine" id="cb231-29" data-line-number="29"><span class="ot">withdrawOp ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">BankOp</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb231-30" data-line-number="30">withdrawOp accountName amount <span class="fu">=</span> <span class="dt">BankOp</span> (withdraw accountName amount)</a></code></pre></div>
|
||
<p>Let’s see how chaining works with these bank operations.</p>
|
||
<div class="sourceCode" id="cb232"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb232-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">let</span> bank <span class="fu">=</span> <span class="dt">Bank</span> (Map.fromList [(<span class="st">"edsger"</span>,<span class="dv">10</span>),(<span class="st">"grace"</span>,<span class="dv">50</span>)])</a>
|
||
<a class="sourceLine" id="cb232-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb232-3" data-line-number="3"><span class="co">-- Running a number of operations using +>></span></a>
|
||
<a class="sourceLine" id="cb232-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb232-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span>) bank</a>
|
||
<a class="sourceLine" id="cb232-6" data-line-number="6">((),<span class="dt">Bank</span> (fromList [(<span class="st">"edsger"</span>,<span class="dv">11</span>),(<span class="st">"grace"</span>,<span class="dv">50</span>)]))</a>
|
||
<a class="sourceLine" id="cb232-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb232-8" data-line-number="8"><span class="dt">Prelude</span><span class="fu">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span> <span class="fu">+>></span> depositOp <span class="st">"grace"</span> <span class="dv">1</span>) bank</a>
|
||
<a class="sourceLine" id="cb232-9" data-line-number="9">((),<span class="dt">Bank</span> (fromList [(<span class="st">"edsger"</span>,<span class="dv">11</span>),(<span class="st">"grace"</span>,<span class="dv">51</span>)]))</a>
|
||
<a class="sourceLine" id="cb232-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb232-11" data-line-number="11"><span class="dt">Prelude</span><span class="fu">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span> <span class="fu">+>></span> depositOp <span class="st">"grace"</span> <span class="dv">1</span> <span class="fu">+>></span> withdrawOp <span class="st">"edsger"</span> <span class="dv">11</span>) bank</a>
|
||
<a class="sourceLine" id="cb232-12" data-line-number="12">(<span class="dv">11</span>,<span class="dt">Bank</span> (fromList [(<span class="st">"edsger"</span>,<span class="dv">0</span>),(<span class="st">"grace"</span>,<span class="dv">51</span>)]))</a>
|
||
<a class="sourceLine" id="cb232-13" data-line-number="13"></a>
|
||
<a class="sourceLine" id="cb232-14" data-line-number="14"><span class="co">-- Using +> to implement a transfer from one account to the other:</span></a>
|
||
<a class="sourceLine" id="cb232-15" data-line-number="15"></a>
|
||
<a class="sourceLine" id="cb232-16" data-line-number="16"><span class="dt">Prelude</span><span class="fu">></span> runBankOp (withdrawOp <span class="st">"edsger"</span> <span class="dv">5</span> <span class="fu">+></span> depositOp <span class="st">"grace"</span>) bank</a>
|
||
<a class="sourceLine" id="cb232-17" data-line-number="17">((),<span class="dt">Bank</span> (fromList [(<span class="st">"edsger"</span>,<span class="dv">5</span>),(<span class="st">"grace"</span>,<span class="dv">55</span>)]))</a>
|
||
<a class="sourceLine" id="cb232-18" data-line-number="18"></a>
|
||
<a class="sourceLine" id="cb232-19" data-line-number="19"><span class="dt">Prelude</span><span class="fu">></span> runBankOp (withdrawOp <span class="st">"edsger"</span> <span class="dv">100</span> <span class="fu">+></span> depositOp <span class="st">"grace"</span>) bank</a>
|
||
<a class="sourceLine" id="cb232-20" data-line-number="20">((),<span class="dt">Bank</span> (fromList [(<span class="st">"edsger"</span>,<span class="dv">0</span>),(<span class="st">"grace"</span>,<span class="dv">60</span>)]))</a></code></pre></div>
|
||
<p>Note how a value of type <code>BankOp</code> represents a process that transforms the bank. The initial state of the bank must be supplied using <code>runBankOp</code>. This makes sense because <code>BankOp</code> transformations can be composed, unlike <code>Bank</code> states. Having to use <code>runBankOp</code> makes the distinction between <em>defining</em> operations and <em>executing them</em> clearer.</p>
|
||
<p>Now that we’re familiar with manipulating <code>BankOp</code> values, we can implement <code>share</code> as a <code>BankOp</code>. We implement a helper <code>distributeOp</code> to make the code a bit neater.</p>
|
||
<div class="sourceCode" id="cb233"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb233-1" data-line-number="1"><span class="co">-- distribute amount to two accounts</span></a>
|
||
<a class="sourceLine" id="cb233-2" data-line-number="2"><span class="ot">distributeOp ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">BankOp</span> ()</a>
|
||
<a class="sourceLine" id="cb233-3" data-line-number="3">distributeOp to1 to2 amount <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb233-4" data-line-number="4"> depositOp to1 half</a>
|
||
<a class="sourceLine" id="cb233-5" data-line-number="5"> <span class="fu">+>></span></a>
|
||
<a class="sourceLine" id="cb233-6" data-line-number="6"> depositOp to2 rest</a>
|
||
<a class="sourceLine" id="cb233-7" data-line-number="7"> <span class="kw">where</span> half <span class="fu">=</span> div amount <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb233-8" data-line-number="8"> rest <span class="fu">=</span> amount <span class="fu">-</span> half</a>
|
||
<a class="sourceLine" id="cb233-9" data-line-number="9"></a>
|
||
<a class="sourceLine" id="cb233-10" data-line-number="10"><span class="ot">shareOp ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">BankOp</span> ()</a>
|
||
<a class="sourceLine" id="cb233-11" data-line-number="11">shareOp from to1 to2 <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb233-12" data-line-number="12"> withdrawOp from <span class="dv">100</span></a>
|
||
<a class="sourceLine" id="cb233-13" data-line-number="13"> <span class="fu">+></span></a>
|
||
<a class="sourceLine" id="cb233-14" data-line-number="14"> distributeOp to1 to2</a></code></pre></div>
|
||
<div class="sourceCode" id="cb234"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb234-1" data-line-number="1">runBankOp (shareOp <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span>)</a>
|
||
<a class="sourceLine" id="cb234-2" data-line-number="2"> (<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">0</span>),(<span class="st">"siegfried"</span>,<span class="dv">0</span>),(<span class="st">"wotan"</span>,<span class="dv">1000</span>)]))</a>
|
||
<a class="sourceLine" id="cb234-3" data-line-number="3"> <span class="fu">==></span> ((),<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">50</span>),(<span class="st">"siegfried"</span>,<span class="dv">50</span>),(<span class="st">"wotan"</span>,<span class="dv">900</span>)]))</a>
|
||
<a class="sourceLine" id="cb234-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb234-5" data-line-number="5">runBankOp (shareOp <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span>)</a>
|
||
<a class="sourceLine" id="cb234-6" data-line-number="6"> (<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">0</span>),(<span class="st">"siegfried"</span>,<span class="dv">0</span>),(<span class="st">"wotan"</span>,<span class="dv">91</span>)]))</a>
|
||
<a class="sourceLine" id="cb234-7" data-line-number="7"> <span class="fu">==></span> ((),<span class="dt">Bank</span> (Map.fromList [(<span class="st">"brunhilde"</span>,<span class="dv">46</span>),(<span class="st">"siegfried"</span>,<span class="dv">45</span>),(<span class="st">"wotan"</span>,<span class="dv">0</span>)]))</a></code></pre></div>
|
||
<p>That was pretty clean wasn’t it? We don’t need to mention the bank at all, we can almost program as if in an imperative language while staying completely pure.</p>
|
||
<p>You can find all of this code in the course repository under <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/Bank.hs"><code>exercises/Examples/Bank.hs</code></a>.</p>
|
||
<h2 id="finally-the-monad-type-class"><span class="header-section-number">13.4</span> Finally: The Monad Type Class</h2>
|
||
<p>We’ve now seen three different types with a chaining operation:</p>
|
||
<div class="sourceCode" id="cb235"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb235-1" data-line-number="1"><span class="ot">(?>) ::</span> <span class="dt">Maybe</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">Maybe</span> b) <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb235-2" data-line-number="2"><span class="ot">(#>) ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">Logger</span> b) <span class="ot">-></span> <span class="dt">Logger</span> b</a>
|
||
<a class="sourceLine" id="cb235-3" data-line-number="3"><span class="ot">(+>) ::</span> <span class="dt">BankOp</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">BankOp</span> b) <span class="ot">-></span> <span class="dt">BankOp</span> b</a></code></pre></div>
|
||
<p>Just like previously with <code>map</code> and <code>Functor</code>, there is a type class that captures this pattern. Note that <code>Monad</code> is a class for <em>type constructors</em>, just like <code>Functor</code>.</p>
|
||
<div class="sourceCode" id="cb236"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb236-1" data-line-number="1"><span class="kw">class</span> <span class="dt">Monad</span> m <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb236-2" data-line-number="2"><span class="ot"> (>>=) ::</span> m a <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m b</a></code></pre></div>
|
||
<p>There are some additional operations in <code>Monad</code> too:</p>
|
||
<div class="sourceCode" id="cb237"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb237-1" data-line-number="1"> <span class="co">-- lift a normal value into the monad</span></a>
|
||
<a class="sourceLine" id="cb237-2" data-line-number="2"><span class="ot"> return ::</span> a <span class="ot">-></span> m a</a>
|
||
<a class="sourceLine" id="cb237-3" data-line-number="3"> <span class="co">-- simpler chaining (like our ##>)</span></a>
|
||
<a class="sourceLine" id="cb237-4" data-line-number="4"><span class="ot"> (>>) ::</span> m a <span class="ot">-></span> m b <span class="ot">-></span> m b</a>
|
||
<a class="sourceLine" id="cb237-5" data-line-number="5"> a <span class="fu">>></span> b <span class="fu">=</span> a <span class="fu">>>=</span> \_ <span class="ot">-></span> b <span class="co">-- remember: _ means ignored argument</span></a></code></pre></div>
|
||
<p>Recall that the <code>Functor</code> class was about a generic <code>map</code> operation. Similarly, the <code>Monad</code> class is just about a generic chaining operation.</p>
|
||
<div class="sourceCode" id="cb238"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb238-1" data-line-number="1">fmap<span class="ot"> ::</span> <span class="dt">Functor</span> f <span class="ot">=></span> (a<span class="ot">-></span>b) <span class="ot">-></span> f a <span class="ot">-></span> f b</a>
|
||
<a class="sourceLine" id="cb238-2" data-line-number="2"><span class="ot">(>>=) ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> m a <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m b</a></code></pre></div>
|
||
<p>The expression <code>operation >>= next</code> takes a monadic operation <code>operation :: m a</code>, and does some further computation with the value that it produces using <code>next :: a -> m b</code>. If this feels too abstract, just recall how chaining works for <code>Maybe</code>:</p>
|
||
<div class="sourceCode" id="cb239"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb239-1" data-line-number="1"><span class="ot">(>>=) ::</span> <span class="dt">Maybe</span> a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">Maybe</span> b) <span class="ot">-></span> <span class="dt">Maybe</span> b</a>
|
||
<a class="sourceLine" id="cb239-2" data-line-number="2"><span class="dt">Nothing</span> <span class="fu">>>=</span> _ <span class="fu">=</span> <span class="dt">Nothing</span> <span class="co">-- if we failed, don't even bother running the next step</span></a>
|
||
<a class="sourceLine" id="cb239-3" data-line-number="3"><span class="dt">Just</span> x <span class="fu">>>=</span> f <span class="fu">=</span> f x <span class="co">-- otherwise run the next step</span></a></code></pre></div>
|
||
<h2 id="maybe-is-a-monad"><span class="header-section-number">13.5</span> Maybe is a Monad!</h2>
|
||
<p>Here’s the full <code>Monad</code> instance for <code>Maybe</code> and some examples.</p>
|
||
<div class="sourceCode" id="cb240"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb240-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Maybe</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb240-2" data-line-number="2"> (<span class="dt">Just</span> x) <span class="fu">>>=</span> k <span class="fu">=</span> k x</a>
|
||
<a class="sourceLine" id="cb240-3" data-line-number="3"> <span class="dt">Nothing</span> <span class="fu">>>=</span> _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb240-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb240-5" data-line-number="5"> (<span class="dt">Just</span> _) <span class="fu">>></span> k <span class="fu">=</span> k</a>
|
||
<a class="sourceLine" id="cb240-6" data-line-number="6"> <span class="dt">Nothing</span> <span class="fu">>></span> _ <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb240-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb240-8" data-line-number="8"> return x <span class="fu">=</span> <span class="dt">Just</span> x</a></code></pre></div>
|
||
<div class="sourceCode" id="cb241"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb241-1" data-line-number="1"><span class="dt">Just</span> <span class="dv">1</span> <span class="fu">>>=</span> \x <span class="ot">-></span> return (x<span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb241-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb241-3" data-line-number="3"><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="fu">>>=</span> (\x <span class="ot">-></span> return (length x)) <span class="fu">>>=</span> (\x <span class="ot">-></span> return (x<span class="fu">+</span><span class="dv">1</span>))</a>
|
||
<a class="sourceLine" id="cb241-4" data-line-number="4"> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb241-5" data-line-number="5"><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="fu">>>=</span> \x <span class="ot">-></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb241-6" data-line-number="6"> <span class="fu">==></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb241-7" data-line-number="7"><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="fu">>></span> <span class="dt">Just</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb241-8" data-line-number="8"> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb241-9" data-line-number="9"><span class="dt">Just</span> <span class="dv">2</span> <span class="fu">>></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb241-10" data-line-number="10"> <span class="fu">==></span> <span class="dt">Nothing</span></a></code></pre></div>
|
||
<p>Here are the <code>stealSecret</code> and <code>increase</code> examples rewritten with monad operations. The changes are <code>?></code> to <code>>>=</code> and <code>Just</code> to <code>return</code>.</p>
|
||
<div class="sourceCode" id="cb242"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb242-1" data-line-number="1"><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb242-2" data-line-number="2">stealSecret password <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb242-3" data-line-number="3"> login password <span class="fu">>>=</span></a>
|
||
<a class="sourceLine" id="cb242-4" data-line-number="4"> secret <span class="fu">>>=</span></a>
|
||
<a class="sourceLine" id="cb242-5" data-line-number="5"> decorate</a>
|
||
<a class="sourceLine" id="cb242-6" data-line-number="6"> <span class="kw">where</span> decorate s <span class="fu">=</span> return (<span class="st">"Stole secret: "</span><span class="fu">++</span>s)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb243"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb243-1" data-line-number="1"><span class="co">-- Set the value of key to val in the given key-value list,</span></a>
|
||
<a class="sourceLine" id="cb243-2" data-line-number="2"><span class="co">-- but only if val is larger than the current value!</span></a>
|
||
<a class="sourceLine" id="cb243-3" data-line-number="3"><span class="ot">increase ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(a,<span class="dt">Int</span>)] <span class="ot">-></span> <span class="dt">Maybe</span> [(a,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb243-4" data-line-number="4">increase key val assocs <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb243-5" data-line-number="5"> lookup key assocs <span class="fu">>>=</span></a>
|
||
<a class="sourceLine" id="cb243-6" data-line-number="6"> check <span class="fu">>>=</span></a>
|
||
<a class="sourceLine" id="cb243-7" data-line-number="7"> buildResult</a>
|
||
<a class="sourceLine" id="cb243-8" data-line-number="8"> <span class="kw">where</span> check x</a>
|
||
<a class="sourceLine" id="cb243-9" data-line-number="9"> <span class="fu">|</span> val <span class="fu"><</span> x <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb243-10" data-line-number="10"> <span class="fu">|</span> otherwise <span class="fu">=</span> return x</a>
|
||
<a class="sourceLine" id="cb243-11" data-line-number="11"> buildResult x <span class="fu">=</span> return ((key,val) <span class="fu">:</span> delete (key,x) assocs)</a></code></pre></div>
|
||
<h2 id="the-return-of-do"><span class="header-section-number">13.6</span> The Return of <code>do</code></h2>
|
||
<p>Here’s an example of what a complex monad operation might look like.</p>
|
||
<div class="sourceCode" id="cb244"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb244-1" data-line-number="1">f <span class="fu">=</span> op1 <span class="fu">>>=</span> continue</a>
|
||
<a class="sourceLine" id="cb244-2" data-line-number="2"> <span class="kw">where</span> continue x <span class="fu">=</span> op2 <span class="fu">>></span> op3 <span class="fu">>>=</span> continue2 x</a>
|
||
<a class="sourceLine" id="cb244-3" data-line-number="3"> continue2 x y <span class="fu">=</span> op4 <span class="fu">>></span> op5 x y</a></code></pre></div>
|
||
<p>Let’s see what happens when we transform this code a bit. First off, let’s inline the definitions.</p>
|
||
<div class="sourceCode" id="cb245"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb245-1" data-line-number="1">f <span class="fu">=</span> op1 <span class="fu">>>=</span> (\x <span class="ot">-></span></a>
|
||
<a class="sourceLine" id="cb245-2" data-line-number="2"> op2 <span class="fu">>></span></a>
|
||
<a class="sourceLine" id="cb245-3" data-line-number="3"> op3 <span class="fu">>>=</span> (\y <span class="ot">-></span></a>
|
||
<a class="sourceLine" id="cb245-4" data-line-number="4"> op4 <span class="fu">>></span></a>
|
||
<a class="sourceLine" id="cb245-5" data-line-number="5"> op5 x y))</a></code></pre></div>
|
||
<p>Due to lambda expressions continuing to the end of the expression, we can omit the parentheses. Let’s also indent differently.</p>
|
||
<div class="sourceCode" id="cb246"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb246-1" data-line-number="1">f <span class="fu">=</span> op1 <span class="fu">>>=</span> \x <span class="ot">-></span></a>
|
||
<a class="sourceLine" id="cb246-2" data-line-number="2"> op2 <span class="fu">>></span></a>
|
||
<a class="sourceLine" id="cb246-3" data-line-number="3"> op3 <span class="fu">>>=</span> \y <span class="ot">-></span></a>
|
||
<a class="sourceLine" id="cb246-4" data-line-number="4"> op4 <span class="fu">>></span></a>
|
||
<a class="sourceLine" id="cb246-5" data-line-number="5"> op5 x y</a></code></pre></div>
|
||
<p>Now we can notice the similarity with <code>do</code> notation. The <code>do</code> block below is actually the same code!</p>
|
||
<div class="sourceCode" id="cb247"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb247-1" data-line-number="1">f <span class="fu">=</span> <span class="kw">do</span> x <span class="ot"><-</span> op1</a>
|
||
<a class="sourceLine" id="cb247-2" data-line-number="2"> op2</a>
|
||
<a class="sourceLine" id="cb247-3" data-line-number="3"> y <span class="ot"><-</span> op3</a>
|
||
<a class="sourceLine" id="cb247-4" data-line-number="4"> op4</a>
|
||
<a class="sourceLine" id="cb247-5" data-line-number="5"> op5 x y</a></code></pre></div>
|
||
<p>To clarify, <code>do</code> notation is just a nicer syntax for the monad operations (<code>>>=</code> and <code>>></code>) and lambdas. Here’s how do notation gets transformed into monad operations. Note! the definition is recursive.</p>
|
||
<div class="sourceCode" id="cb248"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb248-1" data-line-number="1"><span class="kw">do</span> x <span class="ot"><-</span> op a <span class="fu">~~~></span> op a <span class="fu">>>=</span> \x <span class="ot">-></span> <span class="kw">do</span> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb248-2" data-line-number="2"> <span class="fu">...</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb249"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb249-1" data-line-number="1"><span class="kw">do</span> op a <span class="fu">~~~></span> op a <span class="fu">>></span> <span class="kw">do</span> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb249-2" data-line-number="2"> <span class="fu">...</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb250"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb250-1" data-line-number="1"><span class="kw">do</span> <span class="kw">let</span> x <span class="fu">=</span> expr <span class="fu">~~~></span> <span class="kw">let</span> x <span class="fu">=</span> expr <span class="kw">in</span> <span class="kw">do</span> <span class="fu">...</span></a>
|
||
<a class="sourceLine" id="cb250-2" data-line-number="2"> <span class="fu">...</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb251"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb251-1" data-line-number="1"><span class="kw">do</span> finalOp <span class="fu">~~~></span> finalOp</a></code></pre></div>
|
||
<p>Here’s <code>safeNth</code> using do notation:</p>
|
||
<div class="sourceCode" id="cb252"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb252-1" data-line-number="1"><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb252-2" data-line-number="2">safeHead [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb252-3" data-line-number="3">safeHead (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dt">Just</span> x</a>
|
||
<a class="sourceLine" id="cb252-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb252-5" data-line-number="5"><span class="ot">safeTail ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</a>
|
||
<a class="sourceLine" id="cb252-6" data-line-number="6">safeTail [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb252-7" data-line-number="7">safeTail (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dt">Just</span> xs</a>
|
||
<a class="sourceLine" id="cb252-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb252-9" data-line-number="9"><span class="ot">safeNth ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb252-10" data-line-number="10">safeNth <span class="dv">0</span> xs <span class="fu">=</span> safeHead xs</a>
|
||
<a class="sourceLine" id="cb252-11" data-line-number="11">safeNth n xs <span class="fu">=</span> <span class="kw">do</span> t <span class="ot"><-</span> safeTail xs</a>
|
||
<a class="sourceLine" id="cb252-12" data-line-number="12"> safeNth (n<span class="fu">-</span><span class="dv">1</span>) t</a></code></pre></div>
|
||
<p>Here is <code>increase</code> one last time, now with do notation</p>
|
||
<div class="sourceCode" id="cb253"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb253-1" data-line-number="1"><span class="co">-- Set the value of key to val in the given key-value list,</span></a>
|
||
<a class="sourceLine" id="cb253-2" data-line-number="2"><span class="co">-- but only if val is larger than the current value!</span></a>
|
||
<a class="sourceLine" id="cb253-3" data-line-number="3"><span class="ot">increase ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(a,<span class="dt">Int</span>)] <span class="ot">-></span> <span class="dt">Maybe</span> [(a,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb253-4" data-line-number="4">increase key val assocs <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb253-5" data-line-number="5"> <span class="kw">do</span> oldVal <span class="ot"><-</span> lookup key assocs</a>
|
||
<a class="sourceLine" id="cb253-6" data-line-number="6"> check oldVal</a>
|
||
<a class="sourceLine" id="cb253-7" data-line-number="7"> return ((key,val) <span class="fu">:</span> delete (key,oldVal) assocs)</a>
|
||
<a class="sourceLine" id="cb253-8" data-line-number="8"> <span class="kw">where</span> check x</a>
|
||
<a class="sourceLine" id="cb253-9" data-line-number="9"> <span class="fu">|</span> val <span class="fu"><</span> x <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb253-10" data-line-number="10"> <span class="fu">|</span> otherwise <span class="fu">=</span> return x</a></code></pre></div>
|
||
<h2 id="logger-is-a-monad"><span class="header-section-number">13.7</span> Logger is a Monad!</h2>
|
||
<p>We should be able to write a <code>Monad</code> instance for <code>Logger</code> ourselves, by setting <code>>>=</code> to <code>#></code>. However, due to <a href="https://wiki.haskell.org/Functor-Applicative-Monad_Proposal">recent changes in the Haskell language</a> we must implement <code>Functor</code> and <code>Applicative</code> instances to be allowed to implement the <code>Monad</code> instance. <code>Functor</code> we’ve already met, but what’s <code>Applicative</code>? We’ll find out later. Let’s implement the instances:</p>
|
||
<!-- TODO should this be in an Examples file as well? -->
|
||
<div class="sourceCode" id="cb254"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb254-1" data-line-number="1"><span class="kw">import</span> <span class="dt">Control.Monad</span></a>
|
||
<a class="sourceLine" id="cb254-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb254-3" data-line-number="3"><span class="kw">data</span> <span class="dt">Logger</span> a <span class="fu">=</span> <span class="dt">Logger</span> [<span class="dt">String</span>] a <span class="kw">deriving</span> <span class="dt">Show</span></a>
|
||
<a class="sourceLine" id="cb254-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb254-5" data-line-number="5"><span class="ot">msg ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> ()</a>
|
||
<a class="sourceLine" id="cb254-6" data-line-number="6">msg s <span class="fu">=</span> <span class="dt">Logger</span> [s] ()</a>
|
||
<a class="sourceLine" id="cb254-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb254-8" data-line-number="8"><span class="co">-- The Functor instance just maps over the stored value</span></a>
|
||
<a class="sourceLine" id="cb254-9" data-line-number="9"><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Logger</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb254-10" data-line-number="10"> fmap f (<span class="dt">Logger</span> log x) <span class="fu">=</span> <span class="dt">Logger</span> log (f x)</a>
|
||
<a class="sourceLine" id="cb254-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb254-12" data-line-number="12"><span class="co">-- This is an Applicative instance that works for any monad, you</span></a>
|
||
<a class="sourceLine" id="cb254-13" data-line-number="13"><span class="co">-- can just ignore it for now. We'll get back to Applicative later.</span></a>
|
||
<a class="sourceLine" id="cb254-14" data-line-number="14"><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Logger</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb254-15" data-line-number="15"> pure <span class="fu">=</span> return</a>
|
||
<a class="sourceLine" id="cb254-16" data-line-number="16"> (<span class="fu"><*></span>) <span class="fu">=</span> ap</a>
|
||
<a class="sourceLine" id="cb254-17" data-line-number="17"></a>
|
||
<a class="sourceLine" id="cb254-18" data-line-number="18"><span class="co">-- Finally, the Monad instance</span></a>
|
||
<a class="sourceLine" id="cb254-19" data-line-number="19"><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Logger</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb254-20" data-line-number="20"> return x <span class="fu">=</span> <span class="dt">Logger</span> [] x</a>
|
||
<a class="sourceLine" id="cb254-21" data-line-number="21"> <span class="dt">Logger</span> la a <span class="fu">>>=</span> f <span class="fu">=</span> <span class="dt">Logger</span> (la<span class="fu">++</span>lb) b</a>
|
||
<a class="sourceLine" id="cb254-22" data-line-number="22"> <span class="kw">where</span> <span class="dt">Logger</span> lb b <span class="fu">=</span> f a</a></code></pre></div>
|
||
<p>We don’t need the <code>nomsg</code> operation any more since it’s just <code>return</code>. We can also reimplement the <code>annotate</code> operation using monad operations.</p>
|
||
<div class="sourceCode" id="cb255"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb255-1" data-line-number="1"><span class="ot">nomsg ::</span> a <span class="ot">-></span> <span class="dt">Logger</span> a</a>
|
||
<a class="sourceLine" id="cb255-2" data-line-number="2">nomsg x <span class="fu">=</span> return x</a>
|
||
<a class="sourceLine" id="cb255-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb255-4" data-line-number="4"><span class="ot">annotate ::</span> <span class="dt">String</span> <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Logger</span> a</a>
|
||
<a class="sourceLine" id="cb255-5" data-line-number="5">annotate s x <span class="fu">=</span> msg s <span class="fu">>></span> return x</a></code></pre></div>
|
||
<p>Here are the <code>compute</code> and <code>filterLog</code> examples rewritten using do-notation. Note how nice <code>filterLog</code> is with do-notation.</p>
|
||
<div class="sourceCode" id="cb256"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb256-1" data-line-number="1">compute x <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb256-2" data-line-number="2"> a <span class="ot"><-</span> annotate <span class="st">"^2"</span> (x<span class="fu">*</span>x)</a>
|
||
<a class="sourceLine" id="cb256-3" data-line-number="3"> b <span class="ot"><-</span> annotate <span class="st">"+1"</span> (a<span class="fu">+</span><span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb256-4" data-line-number="4"> annotate <span class="st">"*2"</span> (b<span class="fu">*</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb256-5" data-line-number="5"></a>
|
||
<a class="sourceLine" id="cb256-6" data-line-number="6"><span class="ot">filterLog ::</span> (<span class="dt">Show</span> a) <span class="ot">=></span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Logger</span> [a]</a>
|
||
<a class="sourceLine" id="cb256-7" data-line-number="7">filterLog f [] <span class="fu">=</span> return []</a>
|
||
<a class="sourceLine" id="cb256-8" data-line-number="8">filterLog f (x<span class="fu">:</span>xs)</a>
|
||
<a class="sourceLine" id="cb256-9" data-line-number="9"> <span class="fu">|</span> f x <span class="fu">=</span> <span class="kw">do</span> msg (<span class="st">"keeping "</span><span class="fu">++</span>show x)</a>
|
||
<a class="sourceLine" id="cb256-10" data-line-number="10"> xs' <span class="ot"><-</span> filterLog f xs</a>
|
||
<a class="sourceLine" id="cb256-11" data-line-number="11"> return (x<span class="fu">:</span>xs')</a>
|
||
<a class="sourceLine" id="cb256-12" data-line-number="12"> <span class="fu">|</span> otherwise <span class="fu">=</span> <span class="kw">do</span> msg (<span class="st">"dropping "</span><span class="fu">++</span>show x)</a>
|
||
<a class="sourceLine" id="cb256-13" data-line-number="13"> filterLog f xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb257"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb257-1" data-line-number="1">compute <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb257-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"^2"</span>,<span class="st">"+1"</span>,<span class="st">"*2"</span>] <span class="dv">20</span></a>
|
||
<a class="sourceLine" id="cb257-3" data-line-number="3">filterLog (<span class="fu">></span><span class="dv">0</span>) [<span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="fu">-</span><span class="dv">4</span>,<span class="dv">0</span>]</a>
|
||
<a class="sourceLine" id="cb257-4" data-line-number="4"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"keeping 1"</span>,<span class="st">"dropping -2"</span>,<span class="st">"keeping 3"</span>,<span class="st">"dropping -4"</span>,<span class="st">"dropping 0"</span>] [<span class="dv">1</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<h2 id="the-state-monad"><span class="header-section-number">13.8</span> The State Monad</h2>
|
||
<p>Haskell’s <code>State</code> monad is a generalized version of our <code>BankOp</code> type. The <code>State</code> type is parameterized by two types, the first being the type of the state, and the second the type of the value produced. <code>State Bank a</code> would be equivalent to our <code>BankOp a</code>. You can find the <code>State</code> monad in the <a href="https://downloads.haskell.org/~ghc/latest/docs/html/libraries/transformers-0.5.6.2/Control-Monad-Trans-State.html">module <code>Control.Monad.Trans.State</code> of the <code>transformers</code> package</a>. Here’s a simplified implementation of <code>State</code>.</p>
|
||
<div class="sourceCode" id="cb258"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb258-1" data-line-number="1"><span class="kw">data</span> <span class="dt">State</span> s a <span class="fu">=</span> <span class="dt">State</span> (s <span class="ot">-></span> (a,s))</a>
|
||
<a class="sourceLine" id="cb258-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb258-3" data-line-number="3">runState (<span class="dt">State</span> f) s <span class="fu">=</span> f s</a>
|
||
<a class="sourceLine" id="cb258-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb258-5" data-line-number="5"><span class="co">-- operation that overwrites the state (and produces ())</span></a>
|
||
<a class="sourceLine" id="cb258-6" data-line-number="6"><span class="ot">put ::</span> s <span class="ot">-></span> <span class="dt">State</span> s ()</a>
|
||
<a class="sourceLine" id="cb258-7" data-line-number="7">put state <span class="fu">=</span> <span class="dt">State</span> (\oldState <span class="ot">-></span> ((),state))</a>
|
||
<a class="sourceLine" id="cb258-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb258-9" data-line-number="9"><span class="co">-- operation that produces the current state</span></a>
|
||
<a class="sourceLine" id="cb258-10" data-line-number="10"><span class="ot">get ::</span> <span class="dt">State</span> s s</a>
|
||
<a class="sourceLine" id="cb258-11" data-line-number="11">get <span class="fu">=</span> <span class="dt">State</span> (\state <span class="ot">-></span> (state,state))</a>
|
||
<a class="sourceLine" id="cb258-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb258-13" data-line-number="13"><span class="co">-- operation that modifies the current state with a function (and produces ())</span></a>
|
||
<a class="sourceLine" id="cb258-14" data-line-number="14"><span class="ot">modify ::</span> (s <span class="ot">-></span> s) <span class="ot">-></span> <span class="dt">State</span> s ()</a>
|
||
<a class="sourceLine" id="cb258-15" data-line-number="15">modify f <span class="fu">=</span> <span class="dt">State</span> (\state <span class="ot">-></span> ((), f state))</a>
|
||
<a class="sourceLine" id="cb258-16" data-line-number="16"></a>
|
||
<a class="sourceLine" id="cb258-17" data-line-number="17"><span class="co">-- Functor and Applicative instances skipped</span></a>
|
||
<a class="sourceLine" id="cb258-18" data-line-number="18"></a>
|
||
<a class="sourceLine" id="cb258-19" data-line-number="19"><span class="kw">instance</span> <span class="dt">Monad</span> (<span class="dt">State</span> s) <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb258-20" data-line-number="20"> return x <span class="fu">=</span> <span class="dt">State</span> (\s <span class="ot">-></span> (x,s))</a>
|
||
<a class="sourceLine" id="cb258-21" data-line-number="21"></a>
|
||
<a class="sourceLine" id="cb258-22" data-line-number="22"> op <span class="fu">>>=</span> f <span class="fu">=</span> <span class="dt">State</span> h</a>
|
||
<a class="sourceLine" id="cb258-23" data-line-number="23"> <span class="kw">where</span> h state0 <span class="fu">=</span> <span class="kw">let</span> (val,state1) <span class="fu">=</span> runState op state0</a>
|
||
<a class="sourceLine" id="cb258-24" data-line-number="24"> op2 <span class="fu">=</span> f val</a>
|
||
<a class="sourceLine" id="cb258-25" data-line-number="25"> <span class="kw">in</span> runState op2 state1</a></code></pre></div>
|
||
<p>Note how we declare an instance <code>Monad (State s)</code>. We’re using a <em>partially-applied type constructor</em> because instances of <code>Monad</code> can only be declared for type constructors that take one more type parameter. This might be a bit clearer if you look at how <code>m</code>, <code>Maybe</code> and <code>State</code> occur in the type of <code>>>=</code> below.</p>
|
||
<pre><code>class Monad m where
|
||
(>>=) :: m a -> (a -> m b) -> m b
|
||
|
||
instance Monad Maybe where
|
||
(>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
|
||
|
||
instance Monad (State s) where
|
||
(>>=) :: State s a -> (a -> State s b) -> State s b</code></pre>
|
||
<p>Let’s look at some examples of working with <code>State</code>. To start off, let’s consider computations of type <code>State Int a</code>, which represent working with a single counter.</p>
|
||
<div class="sourceCode" id="cb260"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb260-1" data-line-number="1"><span class="co">-- adds i to the value of the counter</span></a>
|
||
<a class="sourceLine" id="cb260-2" data-line-number="2"><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">State</span> <span class="dt">Int</span> ()</a>
|
||
<a class="sourceLine" id="cb260-3" data-line-number="3">add i <span class="fu">=</span> <span class="kw">do</span> old <span class="ot"><-</span> get</a>
|
||
<a class="sourceLine" id="cb260-4" data-line-number="4"> put (old<span class="fu">+</span>i)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb261"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb261-1" data-line-number="1">runState (add <span class="dv">1</span> <span class="fu">>></span> add <span class="dv">3</span> <span class="fu">>></span> add <span class="dv">5</span> <span class="fu">>></span> add <span class="dv">6</span>) <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb261-2" data-line-number="2"> <span class="fu">==></span> ((),<span class="dv">15</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb262"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb262-1" data-line-number="1"><span class="ot">example ::</span> <span class="dt">State</span> <span class="dt">Int</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb262-2" data-line-number="2">example <span class="fu">=</span> <span class="kw">do</span> add <span class="dv">3</span> <span class="co">-- increment state by 3</span></a>
|
||
<a class="sourceLine" id="cb262-3" data-line-number="3"> value <span class="ot"><-</span> get <span class="co">-- value is current state, i.e. initial+3</span></a>
|
||
<a class="sourceLine" id="cb262-4" data-line-number="4"> add <span class="dv">1000</span> <span class="co">-- increment state by 1000</span></a>
|
||
<a class="sourceLine" id="cb262-5" data-line-number="5"> put (value <span class="fu">+</span> <span class="dv">1</span>) <span class="co">-- overwrite state with value+1, i.e. initial+4</span></a>
|
||
<a class="sourceLine" id="cb262-6" data-line-number="6"> return value <span class="co">-- produce value, i.e. intial+3</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb263"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb263-1" data-line-number="1">runState example <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb263-2" data-line-number="2"> <span class="fu">==></span> (<span class="dv">4</span>,<span class="dv">5</span>) <span class="co">-- initial is 1, state is initial+4=5, produces initial+3=4</span></a></code></pre></div>
|
||
<p>Note how a value of type <code>State s a</code> represents a process that transforms the state (just like <code>BankOp</code>). The initial state must be supplied using <code>runState</code>. Again, having to use <code>runState</code> makes the distinction between <em>defining</em> operations and <em>executing them</em> clearer.</p>
|
||
<p>A state can replace an accumulator parameter when processing a list. Here are two examples: finding the largest element of a list, and finding values in a list that occur directly after a <code>0</code>.</p>
|
||
<div class="sourceCode" id="cb264"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb264-1" data-line-number="1"><span class="ot">findLargest ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> [a] <span class="ot">-></span> <span class="dt">State</span> a ()</a>
|
||
<a class="sourceLine" id="cb264-2" data-line-number="2">findLargest [] <span class="fu">=</span> return ()</a>
|
||
<a class="sourceLine" id="cb264-3" data-line-number="3">findLargest (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb264-4" data-line-number="4"> modify (\y <span class="ot">-></span> max x y) <span class="co">-- update state with max of current value and previous largest value</span></a>
|
||
<a class="sourceLine" id="cb264-5" data-line-number="5"> findLargest xs <span class="co">-- process rest of list</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb265"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb265-1" data-line-number="1">runState (findLargest [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">7</span>,<span class="dv">3</span>]) <span class="dv">0</span> <span class="fu">==></span> ((),<span class="dv">7</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb266"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb266-1" data-line-number="1"><span class="co">-- store the given value in the state list</span></a>
|
||
<a class="sourceLine" id="cb266-2" data-line-number="2"><span class="ot">remember ::</span> a <span class="ot">-></span> <span class="dt">State</span> [a] ()</a>
|
||
<a class="sourceLine" id="cb266-3" data-line-number="3">remember x <span class="fu">=</span> modify (x<span class="fu">:</span>)</a>
|
||
<a class="sourceLine" id="cb266-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb266-5" data-line-number="5"><span class="ot">valuesAfterZero ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</a>
|
||
<a class="sourceLine" id="cb266-6" data-line-number="6">valuesAfterZero xs <span class="fu">=</span> runState (go xs) []</a>
|
||
<a class="sourceLine" id="cb266-7" data-line-number="7"> <span class="kw">where</span><span class="ot"> go ::</span> [a] <span class="ot">-></span> <span class="dt">State</span> [a] ()</a>
|
||
<a class="sourceLine" id="cb266-8" data-line-number="8"> go (<span class="dv">0</span><span class="fu">:</span>y<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> remember y</a>
|
||
<a class="sourceLine" id="cb266-9" data-line-number="9"> go (y<span class="fu">:</span>xs)</a>
|
||
<a class="sourceLine" id="cb266-10" data-line-number="10"> go (x<span class="fu">:</span>xs) <span class="fu">=</span> go xs</a>
|
||
<a class="sourceLine" id="cb266-11" data-line-number="11"> go [] <span class="fu">=</span> return ()</a></code></pre></div>
|
||
<div class="sourceCode" id="cb267"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb267-1" data-line-number="1">valuesAfterZero [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">0</span>,<span class="dv">5</span>,<span class="dv">0</span>,<span class="dv">0</span>,<span class="dv">6</span>]</a>
|
||
<a class="sourceLine" id="cb267-2" data-line-number="2"> <span class="fu">==></span> ((),[<span class="dv">6</span>,<span class="dv">0</span>,<span class="dv">5</span>,<span class="dv">4</span>,<span class="dv">1</span>])</a></code></pre></div>
|
||
<h2 id="the-return-of-mapm"><span class="header-section-number">13.9</span> The Return of <code>mapM</code></h2>
|
||
<p>The control structures from the IO lecture work in <em>all monads</em>. Here are their real types.</p>
|
||
<div class="sourceCode" id="cb268"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb268-1" data-line-number="1"><span class="ot">when ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> <span class="dt">Bool</span> <span class="ot">-></span> m () <span class="ot">-></span> m () <span class="co">-- conditional operation</span></a>
|
||
<a class="sourceLine" id="cb268-2" data-line-number="2"><span class="ot">unless ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> <span class="dt">Bool</span> <span class="ot">-></span> m () <span class="ot">-></span> m () <span class="co">-- same, but condition is flipped</span></a>
|
||
<a class="sourceLine" id="cb268-3" data-line-number="3"><span class="ot">replicateM ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> <span class="dt">Int</span> <span class="ot">-></span> m a <span class="ot">-></span> m [a] <span class="co">-- do something many times</span></a>
|
||
<a class="sourceLine" id="cb268-4" data-line-number="4"><span class="ot">replicateM_ ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> <span class="dt">Int</span> <span class="ot">-></span> m a <span class="ot">-></span> m () <span class="co">-- same, but ignore the results</span></a>
|
||
<a class="sourceLine" id="cb268-5" data-line-number="5">mapM<span class="ot"> ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> [a] <span class="ot">-></span> m [b] <span class="co">-- do something on a list's elements</span></a>
|
||
<a class="sourceLine" id="cb268-6" data-line-number="6">mapM_<span class="ot"> ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> [a] <span class="ot">-></span> m () <span class="co">-- same, but ignore the results</span></a>
|
||
<a class="sourceLine" id="cb268-7" data-line-number="7"><span class="ot">forM ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> [a] <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m [b] <span class="co">-- mapM but arguments reversed</span></a>
|
||
<a class="sourceLine" id="cb268-8" data-line-number="8"><span class="ot">forM_ ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> [a] <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m () <span class="co">-- same, but ignore the results</span></a></code></pre></div>
|
||
<p>As we can see here, we can use <code>mapM</code> over all of the monads we’ve met so far:</p>
|
||
<div class="sourceCode" id="cb269"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb269-1" data-line-number="1">mapM (\x <span class="ot">-></span> <span class="kw">if</span> (x<span class="fu">></span><span class="dv">0</span>) <span class="kw">then</span> <span class="dt">Just</span> (x<span class="fu">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">==></span> <span class="dt">Just</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</a>
|
||
<a class="sourceLine" id="cb269-2" data-line-number="2">mapM (\x <span class="ot">-></span> <span class="kw">if</span> (x<span class="fu">></span><span class="dv">0</span>) <span class="kw">then</span> <span class="dt">Just</span> (x<span class="fu">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span>) [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">3</span>] <span class="fu">==></span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb269-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb269-4" data-line-number="4">mapM (\x <span class="ot">-></span> msg <span class="st">"increment"</span> <span class="fu">>></span> msg (show x) <span class="fu">>></span> return (x<span class="fu">+</span><span class="dv">1</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb269-5" data-line-number="5"> <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"increment"</span>,<span class="st">"1"</span>,<span class="st">"increment"</span>,<span class="st">"2"</span>,<span class="st">"increment"</span>,<span class="st">"3"</span>] [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb269-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb269-7" data-line-number="7">runState (mapM (\x <span class="ot">-></span> modify (x<span class="fu">+</span>) <span class="fu">>></span> return (x<span class="fu">+</span><span class="dv">1</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]) <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb269-8" data-line-number="8"> <span class="fu">==></span> ([<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>],<span class="dv">6</span>)</a></code></pre></div>
|
||
<p>Some more examples:</p>
|
||
<div class="sourceCode" id="cb270"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb270-1" data-line-number="1"><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</a>
|
||
<a class="sourceLine" id="cb270-2" data-line-number="2">safeHead [] <span class="fu">=</span> <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb270-3" data-line-number="3">safeHead (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="dt">Just</span> x</a>
|
||
<a class="sourceLine" id="cb270-4" data-line-number="4"><span class="ot">firsts ::</span> [[a]] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</a>
|
||
<a class="sourceLine" id="cb270-5" data-line-number="5">firsts xs <span class="fu">=</span> forM xs safeHead</a></code></pre></div>
|
||
<div class="sourceCode" id="cb271"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb271-1" data-line-number="1">firsts [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">4</span>,<span class="dv">5</span>],[<span class="dv">6</span>]] <span class="fu">==></span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">6</span>]</a>
|
||
<a class="sourceLine" id="cb271-2" data-line-number="2">firsts [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[],[<span class="dv">6</span>]] <span class="fu">==></span> <span class="dt">Nothing</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb272"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb272-1" data-line-number="1"><span class="co">-- an abbreviated version of an example from the last section</span></a>
|
||
<a class="sourceLine" id="cb272-2" data-line-number="2"><span class="ot">findLargest ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> [a] <span class="ot">-></span> <span class="dt">State</span> a ()</a>
|
||
<a class="sourceLine" id="cb272-3" data-line-number="3">findLargest xs <span class="fu">=</span> mapM_ update xs</a>
|
||
<a class="sourceLine" id="cb272-4" data-line-number="4"> <span class="kw">where</span> update x <span class="fu">=</span> modify (\y <span class="ot">-></span> max x y)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb273"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb273-1" data-line-number="1">runState (findLargest [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">7</span>,<span class="dv">3</span>]) <span class="dv">0</span> <span class="fu">==></span> ((),<span class="dv">7</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb274"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb274-1" data-line-number="1"><span class="kw">let</span> increment <span class="fu">=</span> modify (<span class="fu">+</span><span class="dv">1</span>) <span class="fu">>></span> get</a>
|
||
<a class="sourceLine" id="cb274-2" data-line-number="2"> ops <span class="fu">=</span> replicateM <span class="dv">4</span> increment</a>
|
||
<a class="sourceLine" id="cb274-3" data-line-number="3"><span class="kw">in</span> runState ops <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb274-4" data-line-number="4"> <span class="fu">==></span> ([<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>],<span class="dv">4</span>)</a></code></pre></div>
|
||
<p>Here’s <code>filter</code> reimplemented using the <code>State</code> monad:</p>
|
||
<div class="sourceCode" id="cb275"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb275-1" data-line-number="1"><span class="ot">rememberElements ::</span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">State</span> [a] ()</a>
|
||
<a class="sourceLine" id="cb275-2" data-line-number="2">rememberElements f xs <span class="fu">=</span> mapM_ maybePut xs</a>
|
||
<a class="sourceLine" id="cb275-3" data-line-number="3"> <span class="kw">where</span> maybePut x <span class="fu">=</span> when (f x) (modify (<span class="fu">++</span>[x]))</a>
|
||
<a class="sourceLine" id="cb275-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb275-5" data-line-number="5"><span class="ot">sfilter ::</span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> [a]</a>
|
||
<a class="sourceLine" id="cb275-6" data-line-number="6">sfilter f xs <span class="fu">=</span> finalState</a>
|
||
<a class="sourceLine" id="cb275-7" data-line-number="7"> <span class="kw">where</span> (_, finalState) <span class="fu">=</span> runState (rememberElements f xs) []</a></code></pre></div>
|
||
<div class="sourceCode" id="cb276"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb276-1" data-line-number="1">sfilter even [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>]</a>
|
||
<a class="sourceLine" id="cb276-2" data-line-number="2"> <span class="fu">==></span> [<span class="dv">2</span>,<span class="dv">4</span>]</a></code></pre></div>
|
||
<p>We can write our own operations that work for all monads. This is made possible by type classes, as we’ve seen before. If you only use monad operations like <code>return</code> and do-notation, the type system will infer a generic type for your function.</p>
|
||
<div class="sourceCode" id="cb277"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb277-1" data-line-number="1">mywhen b op <span class="fu">=</span> <span class="kw">if</span> b <span class="kw">then</span> op <span class="kw">else</span> return ()</a>
|
||
<a class="sourceLine" id="cb277-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb277-3" data-line-number="3">mymapM_ op [] <span class="fu">=</span> return ()</a>
|
||
<a class="sourceLine" id="cb277-4" data-line-number="4">mymapM_ op (x<span class="fu">:</span>xs) <span class="fu">=</span> <span class="kw">do</span> op x</a>
|
||
<a class="sourceLine" id="cb277-5" data-line-number="5"> mymapM_ op xs</a></code></pre></div>
|
||
<div class="sourceCode" id="cb278"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb278-1" data-line-number="1"><span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> <span class="fu">:</span>t mywhen</a>
|
||
<a class="sourceLine" id="cb278-2" data-line-number="2"><span class="ot">mywhen ::</span> (<span class="dt">Monad</span> m) <span class="ot">=></span> <span class="dt">Bool</span> <span class="ot">-></span> m () <span class="ot">-></span> m ()</a>
|
||
<a class="sourceLine" id="cb278-3" data-line-number="3"><span class="fu">*</span><span class="dt">Main</span><span class="fu">></span> <span class="fu">:</span>t mymapM_</a>
|
||
<a class="sourceLine" id="cb278-4" data-line-number="4"><span class="ot">mymapM_ ::</span> (<span class="dt">Monad</span> m) <span class="ot">=></span> (t <span class="ot">-></span> m a) <span class="ot">-></span> [t] <span class="ot">-></span> m ()</a></code></pre></div>
|
||
<p>We can use these generic operations in each of our example monads:</p>
|
||
<div class="sourceCode" id="cb279"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb279-1" data-line-number="1"><span class="ot">perhapsDecrease ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb279-2" data-line-number="2">perhapsDecrease x <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb279-3" data-line-number="3"> mywhen (x<span class="fu"><=</span><span class="dv">0</span>) <span class="dt">Nothing</span></a>
|
||
<a class="sourceLine" id="cb279-4" data-line-number="4"> return (x<span class="fu">-</span><span class="dv">1</span>)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb280"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb280-1" data-line-number="1">perhapsDecrease <span class="dv">2</span> <span class="fu">==></span> <span class="dt">Just</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb280-2" data-line-number="2">perhapsDecrease <span class="dv">0</span> <span class="fu">==></span> <span class="dt">Nothing</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb281"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb281-1" data-line-number="1"><span class="ot">search ::</span> (<span class="dt">Show</span> a, <span class="dt">Eq</span> a) <span class="ot">=></span> a <span class="ot">-></span> [a] <span class="ot">-></span> <span class="dt">Logger</span> ()</a>
|
||
<a class="sourceLine" id="cb281-2" data-line-number="2">search x ys <span class="fu">=</span> mymapM_ look ys</a>
|
||
<a class="sourceLine" id="cb281-3" data-line-number="3"> <span class="kw">where</span> look y <span class="fu">=</span> mywhen (x<span class="fu">==</span>y) (msg (<span class="st">"Found "</span><span class="fu">++</span>show y))</a></code></pre></div>
|
||
<div class="sourceCode" id="cb282"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb282-1" data-line-number="1">search <span class="dv">3</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">2</span>] <span class="fu">==></span> <span class="dt">Logger</span> [<span class="st">"Found 3"</span>,<span class="st">"Found 3"</span>] ()</a></code></pre></div>
|
||
<div class="sourceCode" id="cb283"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb283-1" data-line-number="1"><span class="ot">sumPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">State</span> <span class="dt">Int</span> ()</a>
|
||
<a class="sourceLine" id="cb283-2" data-line-number="2">sumPositive xs <span class="fu">=</span> mymapM_ f xs</a>
|
||
<a class="sourceLine" id="cb283-3" data-line-number="3"> <span class="kw">where</span> f x <span class="fu">=</span> when (x<span class="fu">></span><span class="dv">0</span>) (modify (x<span class="fu">+</span>))</a></code></pre></div>
|
||
<div class="sourceCode" id="cb284"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb284-1" data-line-number="1">runState (sumPositive [<span class="dv">1</span>,<span class="fu">-</span><span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">3</span>]) <span class="dv">0</span> <span class="fu">==></span> ((),<span class="dv">6</span>)</a></code></pre></div>
|
||
<h2 id="monads-are-functors"><span class="header-section-number">13.10</span> Monads are Functors</h2>
|
||
<p>One useful operation hasn’t yet been introduced: <code>liftM</code>.</p>
|
||
<div class="sourceCode" id="cb285"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb285-1" data-line-number="1"><span class="ot">liftM ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> (a<span class="ot">-></span>b) <span class="ot">-></span> m a <span class="ot">-></span> m b</a>
|
||
<a class="sourceLine" id="cb285-2" data-line-number="2">liftM f op <span class="fu">=</span> <span class="kw">do</span> x <span class="ot"><-</span> op</a>
|
||
<a class="sourceLine" id="cb285-3" data-line-number="3"> return (f x)</a></code></pre></div>
|
||
<p>The <code>liftM</code> operation makes it easy to write code with pure and monadic parts.</p>
|
||
<div class="sourceCode" id="cb286"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb286-1" data-line-number="1">liftM negate (<span class="dt">Just</span> <span class="dv">3</span>)</a>
|
||
<a class="sourceLine" id="cb286-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Just</span> (<span class="fu">-</span><span class="dv">3</span>)</a>
|
||
<a class="sourceLine" id="cb286-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb286-4" data-line-number="4">liftM sort <span class="fu">$</span> firsts [[<span class="dv">4</span>,<span class="dv">6</span>],[<span class="dv">2</span>,<span class="dv">1</span>,<span class="dv">0</span>],[<span class="dv">3</span>,<span class="dv">3</span>,<span class="dv">3</span>]]</a>
|
||
<a class="sourceLine" id="cb286-5" data-line-number="5"> <span class="fu">==></span> <span class="dt">Just</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb286-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb286-7" data-line-number="7">runState (liftM negate get) <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb286-8" data-line-number="8"> <span class="fu">==></span> (<span class="fu">-</span><span class="dv">3</span>,<span class="dv">3</span>)</a></code></pre></div>
|
||
<p>Does the type of <code>liftM</code> look familiar? It’s just like the type of <code>fmap</code>! In fact, it’s easy to define a functor instance for a monad: just set <code>fmap = liftM</code>. Since every <code>Monad</code> needs to be a <code>Functor</code> these days, modern Haskell style prefers <code>fmap</code> over <code>liftM</code>.</p>
|
||
<div class="sourceCode" id="cb287"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb287-1" data-line-number="1">fmap<span class="ot"> ::</span> <span class="dt">Functor</span> f <span class="ot">=></span> (a<span class="ot">-></span>b) <span class="ot">-></span> f a <span class="ot">-></span> f b</a></code></pre></div>
|
||
<div class="sourceCode" id="cb288"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb288-1" data-line-number="1">fmap negate (<span class="dt">Just</span> <span class="dv">3</span>)</a>
|
||
<a class="sourceLine" id="cb288-2" data-line-number="2"> <span class="fu">==></span> <span class="dt">Just</span> (<span class="fu">-</span><span class="dv">3</span>)</a>
|
||
<a class="sourceLine" id="cb288-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb288-4" data-line-number="4">fmap sort <span class="fu">$</span> firsts [[<span class="dv">4</span>,<span class="dv">6</span>],[<span class="dv">2</span>,<span class="dv">1</span>,<span class="dv">0</span>],[<span class="dv">3</span>,<span class="dv">3</span>,<span class="dv">3</span>]]</a>
|
||
<a class="sourceLine" id="cb288-5" data-line-number="5"> <span class="fu">==></span> <span class="dt">Just</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</a>
|
||
<a class="sourceLine" id="cb288-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb288-7" data-line-number="7">runState (fmap negate get) <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb288-8" data-line-number="8"> <span class="fu">==></span> (<span class="fu">-</span><span class="dv">3</span>,<span class="dv">3</span>)</a></code></pre></div>
|
||
<h2 id="one-more-monad"><span class="header-section-number">13.11</span> One More Monad</h2>
|
||
<p><em>The list monad</em> (that is, the <code>Monad</code> instance for <code>[]</code>) represents computations with <em>multiple return values</em>. It’s useful for searching through alternatives. Here’s a first example. For every <code>x</code> we produce both <code>x</code> and <code>-x</code>:</p>
|
||
<div class="sourceCode" id="cb289"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb289-1" data-line-number="1">[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">>>=</span> \x <span class="ot">-></span> [<span class="fu">-</span>x,x]</a>
|
||
<a class="sourceLine" id="cb289-2" data-line-number="2"> <span class="fu">==></span> [<span class="fu">-</span><span class="dv">1</span>,<span class="dv">1</span>,<span class="fu">-</span><span class="dv">2</span>,<span class="dv">2</span>,<span class="fu">-</span><span class="dv">3</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<p>We can filter out unsuitable values by produing an empty list:</p>
|
||
<div class="sourceCode" id="cb290"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb290-1" data-line-number="1">[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="fu">>>=</span> \x <span class="ot">-></span> <span class="kw">if</span> x<span class="fu">></span><span class="dv">1</span> <span class="kw">then</span> [x] <span class="kw">else</span> []</a>
|
||
<a class="sourceLine" id="cb290-2" data-line-number="2"> <span class="fu">==></span> [<span class="dv">2</span>,<span class="dv">3</span>]</a></code></pre></div>
|
||
<p>If we’re using do-notation the list monad starts to look more like a looping construct:</p>
|
||
<div class="sourceCode" id="cb291"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb291-1" data-line-number="1"><span class="kw">do</span> word <span class="ot"><-</span> [<span class="st">"Blue"</span>, <span class="st">"Green"</span>]</a>
|
||
<a class="sourceLine" id="cb291-2" data-line-number="2"> number <span class="ot"><-</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</a>
|
||
<a class="sourceLine" id="cb291-3" data-line-number="3"> return (word <span class="fu">++</span> show number)</a>
|
||
<a class="sourceLine" id="cb291-4" data-line-number="4"> <span class="fu">==></span> [<span class="st">"Blue1"</span>,<span class="st">"Blue2"</span>,<span class="st">"Blue3"</span>,<span class="st">"Green1"</span>,<span class="st">"Green2"</span>,<span class="st">"Green3"</span>]</a></code></pre></div>
|
||
<p>More interesting example: find all the pairs in a list that sum to <code>k</code></p>
|
||
<div class="sourceCode" id="cb292"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb292-1" data-line-number="1"><span class="ot">findSum ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(<span class="dt">Int</span>,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb292-2" data-line-number="2">findSum xs k <span class="fu">=</span> <span class="kw">do</span> a <span class="ot"><-</span> xs</a>
|
||
<a class="sourceLine" id="cb292-3" data-line-number="3"> b <span class="ot"><-</span> xs</a>
|
||
<a class="sourceLine" id="cb292-4" data-line-number="4"> <span class="kw">if</span> (a<span class="fu">+</span>b<span class="fu">==</span>k) <span class="kw">then</span> [(a,b)] <span class="kw">else</span> []</a></code></pre></div>
|
||
<div class="sourceCode" id="cb293"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb293-1" data-line-number="1">findSum [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>] <span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb293-2" data-line-number="2"> <span class="fu">==></span> [(<span class="dv">1</span>,<span class="dv">4</span>),(<span class="dv">2</span>,<span class="dv">3</span>),(<span class="dv">3</span>,<span class="dv">2</span>),(<span class="dv">4</span>,<span class="dv">1</span>)]</a></code></pre></div>
|
||
<p>A final, more complex example. We find all palindromes from a string using the list monad, and then find the longest one.</p>
|
||
<div class="sourceCode" id="cb294"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb294-1" data-line-number="1"><span class="kw">import</span> <span class="dt">Data.List</span> (sortBy)</a>
|
||
<a class="sourceLine" id="cb294-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb294-3" data-line-number="3"><span class="ot">substrings ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb294-4" data-line-number="4">substrings xs <span class="fu">=</span> <span class="kw">do</span> start <span class="ot"><-</span> [<span class="dv">0</span><span class="fu">..</span>length xs <span class="fu">-</span> <span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb294-5" data-line-number="5"> end <span class="ot"><-</span> [start<span class="fu">+</span><span class="dv">1</span><span class="fu">..</span>length xs <span class="fu">-</span> <span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb294-6" data-line-number="6"> return <span class="fu">$</span> drop start <span class="fu">$</span> take end <span class="fu">$</span> xs</a>
|
||
<a class="sourceLine" id="cb294-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb294-8" data-line-number="8"><span class="ot">palindromesIn ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</a>
|
||
<a class="sourceLine" id="cb294-9" data-line-number="9">palindromesIn xs <span class="fu">=</span> <span class="kw">do</span> s <span class="ot"><-</span> substrings xs</a>
|
||
<a class="sourceLine" id="cb294-10" data-line-number="10"> <span class="kw">if</span> (s<span class="fu">==</span>reverse s) <span class="kw">then</span> return s <span class="kw">else</span> []</a>
|
||
<a class="sourceLine" id="cb294-11" data-line-number="11"></a>
|
||
<a class="sourceLine" id="cb294-12" data-line-number="12">longestPalindrome xs <span class="fu">=</span> head <span class="fu">.</span> sortBy f <span class="fu">$</span> palindromesIn xs</a>
|
||
<a class="sourceLine" id="cb294-13" data-line-number="13"> <span class="kw">where</span> f s s' <span class="fu">=</span> compare (length s') (length s) <span class="co">-- longer is smaller</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb295"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb295-1" data-line-number="1">palindromesIn <span class="st">"aabbacddcaca"</span></a>
|
||
<a class="sourceLine" id="cb295-2" data-line-number="2"> <span class="fu">==></span> [<span class="st">"a"</span>,<span class="st">"aa"</span>,<span class="st">"a"</span>,<span class="st">"abba"</span>,<span class="st">"b"</span>,<span class="st">"bb"</span>,<span class="st">"b"</span>,<span class="st">"a"</span>,<span class="st">"acddca"</span>,<span class="st">"c"</span>,<span class="st">"cddc"</span>,<span class="st">"d"</span>,<span class="st">"dd"</span>,<span class="st">"d"</span>,<span class="st">"c"</span>,<span class="st">"cac"</span>,<span class="st">"a"</span>,<span class="st">"c"</span>]</a>
|
||
<a class="sourceLine" id="cb295-3" data-line-number="3">longestPalindrome <span class="st">"aabbacddcaca"</span></a>
|
||
<a class="sourceLine" id="cb295-4" data-line-number="4"> <span class="fu">==></span> <span class="st">"acddca"</span></a></code></pre></div>
|
||
<p>Here’s the surprisingly simple implementation of the list monad:</p>
|
||
<div class="sourceCode" id="cb296"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb296-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">Monad</span> [] <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb296-2" data-line-number="2"> return x <span class="fu">=</span> [x] <span class="co">-- an operation that produces one value</span></a>
|
||
<a class="sourceLine" id="cb296-3" data-line-number="3"> lis <span class="fu">>>=</span> f <span class="fu">=</span> concat (map f lis) <span class="co">-- compute f for all values, combine the results</span></a></code></pre></div>
|
||
<p>We’ve actually seen the list monad previously in the guise of list comprehensions. Compare this reimplementation of <code>findSum</code> to the earlier one that uses <code>do</code>-notation.</p>
|
||
<div class="sourceCode" id="cb297"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb297-1" data-line-number="1"><span class="ot">findSum ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> [(<span class="dt">Int</span>,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb297-2" data-line-number="2">findSum xs k <span class="fu">=</span> [(a,b) <span class="fu">|</span> a <span class="ot"><-</span> xs, b <span class="ot"><-</span> xs, a<span class="fu">+</span>b<span class="fu">==</span>k ]</a></code></pre></div>
|
||
<h2 id="oh-right-io"><span class="header-section-number">13.12</span> Oh Right, IO</h2>
|
||
<p>As you’ve probably guessed by now, <code>IO</code> is a monad. However the implementations of the <code>IO</code> type and <code>instance Monad IO</code> are compiler built-ins. You couldn’t implement the IO monad just using standard Haskell, unlike <code>Maybe</code> monad, <code>State</code> monad and other monads we’ve seen.</p>
|
||
<p>However, true side effects fit the monad pattern just like <code>State</code> and <code>Maybe</code>. Just like with other monads, we’re separating the <em>pure definitions of operations</em> from the process of <em>running the operations</em>. As a bonus, you can use all the generic monad operations (<code>mapM</code> and friends) with IO.</p>
|
||
<p>Here are some examples of writing IO using monad operations.</p>
|
||
<div class="sourceCode" id="cb298"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb298-1" data-line-number="1"><span class="ot">printTwoThings ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb298-2" data-line-number="2">printTwoThings <span class="fu">=</span> putStrLn <span class="st">"One!"</span> <span class="fu">>></span> print <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb298-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb298-4" data-line-number="4"><span class="ot">echo ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb298-5" data-line-number="5">echo <span class="fu">=</span> getLine <span class="fu">>>=</span> putStrLn</a>
|
||
<a class="sourceLine" id="cb298-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb298-7" data-line-number="7"><span class="ot">verboseEcho ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb298-8" data-line-number="8">verboseEcho <span class="fu">=</span> getLine <span class="fu">>>=</span> \s <span class="ot">-></span> putStrLn (<span class="st">"You wrote: "</span> <span class="fu">++</span> s)</a>
|
||
<a class="sourceLine" id="cb298-9" data-line-number="9"></a>
|
||
<a class="sourceLine" id="cb298-10" data-line-number="10"><span class="ot">query ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb298-11" data-line-number="11">query question <span class="fu">=</span> putStrLn question <span class="fu">>></span> getLine</a>
|
||
<a class="sourceLine" id="cb298-12" data-line-number="12"></a>
|
||
<a class="sourceLine" id="cb298-13" data-line-number="13"><span class="ot">confirm ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb298-14" data-line-number="14">confirm question <span class="fu">=</span> putStrLn question <span class="fu">>></span> fmap interpret getLine</a>
|
||
<a class="sourceLine" id="cb298-15" data-line-number="15"> <span class="kw">where</span> interpret <span class="st">"Y"</span> <span class="fu">=</span> <span class="dt">True</span></a>
|
||
<a class="sourceLine" id="cb298-16" data-line-number="16"> interpret _ <span class="fu">=</span> <span class="dt">False</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb299"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb299-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> printTwoThings</a>
|
||
<a class="sourceLine" id="cb299-2" data-line-number="2"><span class="dt">One</span><span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb299-3" data-line-number="3"><span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb299-4" data-line-number="4"></a>
|
||
<a class="sourceLine" id="cb299-5" data-line-number="5"><span class="dt">Prelude</span><span class="fu">></span> verboseEcho</a>
|
||
<a class="sourceLine" id="cb299-6" data-line-number="6"><span class="dt">The</span> <span class="dt">Iliad</span></a>
|
||
<a class="sourceLine" id="cb299-7" data-line-number="7"><span class="dt">You</span> wrote<span class="fu">:</span> <span class="dt">The</span> <span class="dt">Iliad</span></a>
|
||
<a class="sourceLine" id="cb299-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb299-9" data-line-number="9"><span class="dt">Prelude</span><span class="fu">></span> answer <span class="ot"><-</span> query <span class="st">"Why am I here?"</span></a>
|
||
<a class="sourceLine" id="cb299-10" data-line-number="10"><span class="dt">Why</span> am <span class="dt">I</span> here<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb299-11" data-line-number="11"><span class="dt">Good</span> question<span class="fu">!</span></a>
|
||
<a class="sourceLine" id="cb299-12" data-line-number="12"><span class="dt">Prelude</span><span class="fu">></span> answer</a>
|
||
<a class="sourceLine" id="cb299-13" data-line-number="13"><span class="st">"Good question!"</span></a>
|
||
<a class="sourceLine" id="cb299-14" data-line-number="14"></a>
|
||
<a class="sourceLine" id="cb299-15" data-line-number="15"><span class="dt">Prelude</span><span class="fu">></span> b <span class="ot"><-</span> confirm <span class="st">"Fire warheads?"</span></a>
|
||
<a class="sourceLine" id="cb299-16" data-line-number="16"><span class="dt">Fire</span> warheads<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb299-17" data-line-number="17">no no no no</a>
|
||
<a class="sourceLine" id="cb299-18" data-line-number="18"><span class="dt">Prelude</span><span class="fu">></span> b</a>
|
||
<a class="sourceLine" id="cb299-19" data-line-number="19"><span class="dt">False</span></a>
|
||
<a class="sourceLine" id="cb299-20" data-line-number="20"><span class="dt">Prelude</span><span class="fu">></span> b <span class="ot"><-</span> confirm <span class="st">"Make love, not war?"</span></a>
|
||
<a class="sourceLine" id="cb299-21" data-line-number="21"><span class="dt">Make</span> love, not war<span class="fu">?</span></a>
|
||
<a class="sourceLine" id="cb299-22" data-line-number="22"><span class="dt">Y</span></a>
|
||
<a class="sourceLine" id="cb299-23" data-line-number="23"><span class="dt">Prelude</span><span class="fu">></span> b</a>
|
||
<a class="sourceLine" id="cb299-24" data-line-number="24"><span class="dt">True</span></a></code></pre></div>
|
||
<h2 id="monads-in-other-languages"><span class="header-section-number">13.13</span> Monads in Other Languages</h2>
|
||
<p>Once you’ve gotten familiar with the concept of a monad, you’ll start seeing monadlike things in other languages too. The most well-known examples of this are <em>Option types</em>, <em>Java Streams</em> and <em>JavaScript promises</em> . If you know these languages or concepts from before, you might find this section illuminating. If you don’t, feel free to skip this.</p>
|
||
<h3 id="optionals"><span class="header-section-number">13.13.1</span> Optionals</h3>
|
||
<p>Many langages have an <a href="https://en.wikipedia.org/wiki/Option_type">option type</a>. This type is called <code>Optional<T></code> in Java, <code>std::optional<T></code> in C++, <code>Nullable<T></code> in C#, and so on. These types often have behaviour resembling the Haskell <code>Maybe</code> monad, for example:</p>
|
||
<ul>
|
||
<li>In Java, <a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/Optional.html#flatMap(java.util.function.Function)"><code>Optional.flatMap</code></a> corresponds to <code>>>=</code>: it lets you apply a <code>Function<T,<Optional<U>></code> to an <code>Optional<T></code> and get an <code>Optional<U></code>.</li>
|
||
<li>In C#, binary operations get automatically <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types#lifted-operators">lifted</a> to <code>Nullable</code> types. For example, <code>a + null</code> becomes <code>null</code>.</li>
|
||
</ul>
|
||
<h3 id="streams"><span class="header-section-number">13.13.2</span> Streams</h3>
|
||
<p><a href="https://docs.oracle.com/en/java/javase/14/docs/api/java.base/java/util/stream/Stream.html">Java Streams</a> have a monadlike API too. Streams are about producing many values incrementally. Just like with Optional, the method <code>Stream.flatMap</code> lets us take a <code>Stream<T></code>, combine it with a <code>Function<T,Stream<U>></code> and get a <code>Stream<U></code>.</p>
|
||
<p>As an example, if <code>lines</code> is a <code>Stream<String></code>, <code>words</code> takes a <code>String</code> and returns a <code>Stream<String></code> and <code>readInt</code> takes a <code>String</code> and returns an <code>Integer</code>, we can write:</p>
|
||
<div class="sourceCode" id="cb300"><pre class="sourceCode java"><code class="sourceCode java"><a class="sourceLine" id="cb300-1" data-line-number="1">Stream<<span class="bu">Integer</span>> <span class="fu">parseNumbers</span>(Stream<<span class="bu">String</span>> lines) {</a>
|
||
<a class="sourceLine" id="cb300-2" data-line-number="2"> <span class="kw">return</span> lines.<span class="fu">flatMap</span>(words).<span class="fu">map</span>(read);</a>
|
||
<a class="sourceLine" id="cb300-3" data-line-number="3">}</a></code></pre></div>
|
||
<p>This corresponds to the following Haskell list monad code:</p>
|
||
<div class="sourceCode" id="cb301"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb301-1" data-line-number="1"><span class="ot">parseNumbers ::</span> [<span class="dt">String</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</a>
|
||
<a class="sourceLine" id="cb301-2" data-line-number="2">parseNumbers strings <span class="fu">=</span> fmap read (strings <span class="fu">>>=</span> words)</a></code></pre></div>
|
||
<div class="sourceCode" id="cb302"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb302-1" data-line-number="1">parseNumbers [<span class="st">"123 456"</span>,<span class="st">"7 89"</span>] <span class="fu">==></span> [<span class="dv">123</span>,<span class="dv">456</span>,<span class="dv">7</span>,<span class="dv">89</span>]</a></code></pre></div>
|
||
<h3 id="promises"><span class="header-section-number">13.13.3</span> Promises</h3>
|
||
<p>There is <a href="https://hackernoon.com/functional-javascript-functors-monads-and-promises-679ce2ab8abe">much</a> <a href="https://stackoverflow.com/questions/45712106/why-are-promises-monads">disagreement</a> about whether Promises in JavaScript <em>really</em> are monads or not. However, some similarities are obvious.</p>
|
||
<p>First, consider the similarities between <code>Promise.then</code> and <code>>>=</code>. Both take an <em>operation</em> (promise or monadic operation), and combine it with a function that returns a new operation.</p>
|
||
<div class="sourceCode" id="cb303"><pre class="sourceCode javascript"><code class="sourceCode javascript"><a class="sourceLine" id="cb303-1" data-line-number="1"><span class="kw">function</span> <span class="at">concatPromises</span>(promise1<span class="op">,</span> promise2) <span class="op">{</span></a>
|
||
<a class="sourceLine" id="cb303-2" data-line-number="2"> <span class="cf">return</span> <span class="va">promise1</span>.<span class="at">then</span>(value1 <span class="op">=></span> <span class="va">promise2</span>.<span class="at">then</span>(value2 <span class="op">=></span> value1<span class="op">+</span>value2))<span class="op">;</span></a>
|
||
<a class="sourceLine" id="cb303-3" data-line-number="3"><span class="op">}</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb304"><pre class="sourceCode javascript"><code class="sourceCode javascript"><a class="sourceLine" id="cb304-1" data-line-number="1"><span class="op">>></span> <span class="at">concatPromises</span>(<span class="va">Promise</span>.<span class="at">resolve</span>(<span class="st">"abc"</span>)<span class="op">,</span> <span class="va">Promise</span>.<span class="at">resolve</span>(<span class="st">"def"</span>)).<span class="at">then</span>(<span class="va">console</span>.<span class="at">log</span>)</a>
|
||
<a class="sourceLine" id="cb304-2" data-line-number="2">abcdef</a></code></pre></div>
|
||
<div class="sourceCode" id="cb305"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb305-1" data-line-number="1"><span class="ot">concatMonadic ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> m <span class="dt">String</span> <span class="ot">-></span> m <span class="dt">String</span> <span class="ot">-></span> m <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb305-2" data-line-number="2">concatMonadic op1 op2 <span class="fu">=</span> op1 <span class="fu">>>=</span> (\value1 <span class="ot">-></span> op2 <span class="fu">>>=</span> (\value2 <span class="ot">-></span> return (value1<span class="fu">++</span>value2)))</a></code></pre></div>
|
||
<div class="sourceCode" id="cb306"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb306-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> concatMonadic (<span class="dt">Just</span> <span class="st">"abc"</span>) (<span class="dt">Just</span> <span class="st">"def"</span>)</a>
|
||
<a class="sourceLine" id="cb306-2" data-line-number="2"><span class="dt">Just</span> <span class="st">"abcdef"</span></a></code></pre></div>
|
||
<p>Next, let’s consider the similarities between async/await and do-notation. Both are nicer syntaxes for working with the raw <code>Promise.then</code> or <code>>>=</code> mechanisms. We reimplement <code>concatPromises</code> using async/await, and <code>concatMonadic</code> using do-notation. Their behaviour stays the same.</p>
|
||
<div class="sourceCode" id="cb307"><pre class="sourceCode javascript"><code class="sourceCode javascript"><a class="sourceLine" id="cb307-1" data-line-number="1">async <span class="kw">function</span> <span class="at">concatPromises</span>(promise1<span class="op">,</span> promise2) <span class="op">{</span></a>
|
||
<a class="sourceLine" id="cb307-2" data-line-number="2"> <span class="kw">let</span> value1 <span class="op">=</span> await promise1<span class="op">;</span></a>
|
||
<a class="sourceLine" id="cb307-3" data-line-number="3"> <span class="kw">let</span> value2 <span class="op">=</span> await promise2<span class="op">;</span></a>
|
||
<a class="sourceLine" id="cb307-4" data-line-number="4"> <span class="cf">return</span> value1<span class="op">+</span>value2<span class="op">;</span></a>
|
||
<a class="sourceLine" id="cb307-5" data-line-number="5"><span class="op">}</span></a></code></pre></div>
|
||
<div class="sourceCode" id="cb308"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb308-1" data-line-number="1"><span class="ot">concatMonadic ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> m <span class="dt">String</span> <span class="ot">-></span> m <span class="dt">String</span> <span class="ot">-></span> m <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb308-2" data-line-number="2">concatMonadic op1 op2 <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb308-3" data-line-number="3"> value1 <span class="ot"><-</span> op1</a>
|
||
<a class="sourceLine" id="cb308-4" data-line-number="4"> value2 <span class="ot"><-</span> op2</a>
|
||
<a class="sourceLine" id="cb308-5" data-line-number="5"> return (value1<span class="fu">++</span>value2)</a></code></pre></div>
|
||
<h2 id="monads-wrap-up"><span class="header-section-number">13.14</span> Monads: Wrap-up</h2>
|
||
<ul>
|
||
<li>The <code>Monad</code> type class is a way to represent different ways of <em>executing recipes</em>
|
||
<ul>
|
||
<li>failure (<code>Maybe</code>)</li>
|
||
<li>logging</li>
|
||
<li>state</li>
|
||
<li>nondeterminism (the list monad)</li>
|
||
<li>IO</li>
|
||
</ul></li>
|
||
<li>You can write monad code in two equivalent ways:
|
||
<ul>
|
||
<li>Using the <code>Monad</code> class operations (<code>>>=</code>, <code>>></code>) directly</li>
|
||
<li>Using <code>do</code>-notation</li>
|
||
</ul></li>
|
||
<li>When <code>M</code> is a monad, values of type <code>M a</code> are <em>operations that produce a result of type <code>a</code></em></li>
|
||
<li>Monads are a <em>design pattern</em> and a <em>library</em> (<code>mapM</code> etc)
|
||
<ul>
|
||
<li>Using common abstractions makes it easier to understand code</li>
|
||
<li>Reading a <code>State</code> operation is easier than deciphering a complicated recursion with state</li>
|
||
</ul></li>
|
||
<li>Everything you can do with monads, you can also do without them
|
||
<ul>
|
||
<li>Exception: IO</li>
|
||
<li>Using a monad often simplifies code</li>
|
||
</ul></li>
|
||
<li><em>Warning</em>: the internet is full of tutorials trying to explain monads using a simple analogy
|
||
<ul>
|
||
<li>In my experience, this doesn’t work</li>
|
||
<li>What works is using different monads and slowly getting used to the concept</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h2 id="sidenote-standard-haskell"><span class="header-section-number">13.15</span> Sidenote: Standard Haskell</h2>
|
||
<p>This and the previous lecture have covered many parts where the GHC version of Haskell differs from standard Haskell 2010. Here’s a short list of the changes GHC has made, just so you know:</p>
|
||
<ul>
|
||
<li><code>length</code>, <code>sum</code>, <code>foldr</code> etc. generalized to work on <code>Foldable</code> instead of just lists</li>
|
||
<li><code>Functor</code> and <code>Applicative</code> are superclasses of <code>Monad</code></li>
|
||
<li>The <code>fail</code> method has been moved from the <code>Monad</code> type class to its own <code>MonadFail</code> class</li>
|
||
</ul>
|
||
<h2 id="quiz-4"><span class="header-section-number">13.16</span> Quiz</h2>
|
||
<p>What is the expression equivalent to the following do block?</p>
|
||
<div class="sourceCode" id="cb309"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb309-1" data-line-number="1"><span class="kw">do</span> y <span class="ot"><-</span> z</a>
|
||
<a class="sourceLine" id="cb309-2" data-line-number="2"> s y</a>
|
||
<a class="sourceLine" id="cb309-3" data-line-number="3"> return (f y)</a></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>z >> \y -> s y >> return (f y)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>z >>= \y -> s y >> return (f y)</code>
|
||
</li>
|
||
<li>
|
||
<code>z >> \y -> s y >>= return (f y)</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>\x xs -> return (x : xs)</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>Monad m => a -> [a] -> m [a]</code>
|
||
</li>
|
||
<li>
|
||
<code>Monad m => a -> [m a] -> [m a]</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> [a] -> Monad [a]</code>
|
||
</li>
|
||
<li>
|
||
None of the above
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>\x xs -> return x : xs</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Monad m => a -> [a] -> m [a]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Monad m => a -> [m a] -> [m a]</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> [a] -> Monad [a]</code>
|
||
</li>
|
||
<li>
|
||
None of the above
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>(\x xs -> return x) : xs</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Monad m => a -> [a] -> m [a]</code>
|
||
</li>
|
||
<li>
|
||
<code>Monad m => a -> [m a] -> [m a]</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> [a] -> Monad [a]</code>
|
||
</li>
|
||
<li class="correct">
|
||
None of the above
|
||
</li>
|
||
</ol>
|
||
<h2 id="exercises-4"><span class="header-section-number">13.17</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set13a.hs">Set13a</a></li>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set13b.hs">Set13b</a></li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
<h1 id="lecture-14-lets-use-some-libraries"><span class="header-section-number">14</span> Lecture 14: Let’s Use Some Libraries!</h1>
|
||
<p>Now that you know monads, you pretty much know everything about Haskell to start writing real programs that use libraries to do useful things. This lecture will go over some examples of libraries that are commonly used in such real programs. Using these libraries is also a good way to practice using monads, reading docs, and understanding type errors.</p>
|
||
<h2 id="text-and-bytestring"><span class="header-section-number">14.1</span> <code>Text</code> and <code>ByteString</code></h2>
|
||
<p>So far, we’ve been using the Haskell <code>String</code> type to work with strings. However <code>String</code> is just <code>[Char]</code>, a linked list of characters. This is horribly inefficient, both in terms of memory, and in terms of time. Once we move beyond processing short strings and start processing whole files or network requests, a more time efficient string type becomes a must.</p>
|
||
<p>There are two types that are used as replacements for <code>String</code>, with slightly different semantics:</p>
|
||
<ul>
|
||
<li><code>Data.Text</code> represents <em>a sequence of <a href="https://en.wikipedia.org/wiki/Unicode">Unicode characters</a></em>, just like <code>String</code>, only more efficient. Used when dealing with text.</li>
|
||
<li><code>Data.ByteString</code> represents <em>a sequence of bytes</em>. Used when dealing with binary data.</li>
|
||
</ul>
|
||
<p>Additionally, both of these types come in <em>lazy</em> and <em>strict</em> variants. The <a href="https://hackage.haskell.org/package/text-1.2.2.2/docs/Data-Text.html">docs for <code>Data.Text</code></a> summarize the difference well:</p>
|
||
<blockquote>
|
||
<p>The strict <code>Text</code> type requires that an entire string fit into memory at once. The lazy <code>Text</code> type is capable of streaming strings that are larger than memory using a small memory footprint… Each module provides an almost identical API…</p>
|
||
</blockquote>
|
||
<p>All of these types (<code>Text</code> and <code>ByteString</code>, strict and lazy) offer <code>pack</code> and <code>unpack</code> functions for converting from and to plain <code>String</code>s. The types also come with specialized versions of familiar list functions like <code>reverse</code>, <code>take</code>, <code>map</code> and so on.</p>
|
||
<h3 id="examples-with-text"><span class="header-section-number">14.1.1</span> Examples with <code>Text</code></h3>
|
||
<p>Let’s go through a short GHCi session demonstrating the use of <code>Data.Text</code>. As <a href="https://hackage.haskell.org/package/text-1.2.2.2/docs/Data-Text.html">the documentation</a> says, the <code>Data.Text</code> module is designed to be imported <em>qualified</em>. We can convert a <code>String</code> into a <code>Text</code> with the function <code>T.pack</code>. Note how a value of type <code>Text</code> gets printed just like a <code>String</code>.</p>
|
||
<div class="sourceCode" id="cb310"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb310-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></a>
|
||
<a class="sourceLine" id="cb310-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="fu">:</span>t T.pack</a>
|
||
<a class="sourceLine" id="cb310-3" data-line-number="3">T.pack<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">T.Text</span></a>
|
||
<a class="sourceLine" id="cb310-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">let</span> phrase <span class="fu">=</span> T.pack <span class="st">"brevity is the soul of wit"</span></a>
|
||
<a class="sourceLine" id="cb310-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="fu">:</span>t phrase</a>
|
||
<a class="sourceLine" id="cb310-6" data-line-number="6"><span class="ot">phrase ::</span> <span class="dt">T.Text</span></a>
|
||
<a class="sourceLine" id="cb310-7" data-line-number="7"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> phrase</a>
|
||
<a class="sourceLine" id="cb310-8" data-line-number="8"><span class="st">"brevity is the soul of wit"</span></a></code></pre></div>
|
||
<p>We can use the functions from <code>Data.Text</code> to operate on values of <code>Text</code>. Many of these are named like their counterparts for <code>String</code>s or lists from <code>Prelude</code>.</p>
|
||
<div class="sourceCode" id="cb311"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb311-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="fu">:</span>t T.length</a>
|
||
<a class="sourceLine" id="cb311-2" data-line-number="2">T.length<span class="ot"> ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb311-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.length phrase</a>
|
||
<a class="sourceLine" id="cb311-4" data-line-number="4"><span class="dv">26</span></a>
|
||
<a class="sourceLine" id="cb311-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.head phrase</a>
|
||
<a class="sourceLine" id="cb311-6" data-line-number="6"><span class="ch">'b'</span></a>
|
||
<a class="sourceLine" id="cb311-7" data-line-number="7"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.take <span class="dv">4</span> phrase</a>
|
||
<a class="sourceLine" id="cb311-8" data-line-number="8"><span class="st">"brev"</span></a>
|
||
<a class="sourceLine" id="cb311-9" data-line-number="9"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="fu">:</span>t T.words</a>
|
||
<a class="sourceLine" id="cb311-10" data-line-number="10">T.words<span class="ot"> ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> [<span class="dt">T.Text</span>]</a>
|
||
<a class="sourceLine" id="cb311-11" data-line-number="11"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.words phrase</a>
|
||
<a class="sourceLine" id="cb311-12" data-line-number="12">[<span class="st">"brevity"</span>,<span class="st">"is"</span>,<span class="st">"the"</span>,<span class="st">"soul"</span>,<span class="st">"of"</span>,<span class="st">"wit"</span>]</a>
|
||
<a class="sourceLine" id="cb311-13" data-line-number="13"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="fu">:</span>t T.map</a>
|
||
<a class="sourceLine" id="cb311-14" data-line-number="14">T.map<span class="ot"> ::</span> (<span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Char</span>) <span class="ot">-></span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">T.Text</span></a>
|
||
<a class="sourceLine" id="cb311-15" data-line-number="15"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.map (\c <span class="ot">-></span> <span class="kw">if</span> c<span class="fu">==</span><span class="ch">'o'</span> <span class="kw">then</span> <span class="ch">'0'</span> <span class="kw">else</span> c) phrase</a>
|
||
<a class="sourceLine" id="cb311-16" data-line-number="16"><span class="st">"brevity is the s0ul 0f wit"</span></a></code></pre></div>
|
||
<p>A useful detail is that <code>Text</code> has a <code>Monoid</code> instance that glues <code>Text</code> values together. You can also use the functions <code>T.append</code> and <code>T.concat</code>.</p>
|
||
<div class="sourceCode" id="cb312"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb312-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> phrase <span class="fu"><></span> phrase</a>
|
||
<a class="sourceLine" id="cb312-2" data-line-number="2"><span class="st">"brevity is the soul of witbrevity is the soul of wit"</span></a>
|
||
<a class="sourceLine" id="cb312-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.append phrase phrase</a>
|
||
<a class="sourceLine" id="cb312-4" data-line-number="4"><span class="st">"brevity is the soul of witbrevity is the soul of wit"</span></a>
|
||
<a class="sourceLine" id="cb312-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.concat [phrase,phrase,phrase]</a>
|
||
<a class="sourceLine" id="cb312-6" data-line-number="6"><span class="st">"brevity is the soul of witbrevity is the soul of witbrevity is the soul of wit"</span></a></code></pre></div>
|
||
<p>If you want to write a recursive function that pattern matches on a <code>Text</code> like you would on a <code>String</code>, you can use the function <code>T.uncons :: T.Text -> Maybe (Char, T.Text)</code> to split a <code>Text</code> into a head and a tail. Here’s a simple example:</p>
|
||
<div class="sourceCode" id="cb313"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb313-1" data-line-number="1"><span class="ot">countLetter ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb313-2" data-line-number="2">countLetter c t <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb313-3" data-line-number="3"> <span class="kw">case</span> T.uncons t <span class="kw">of</span></a>
|
||
<a class="sourceLine" id="cb313-4" data-line-number="4"> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb313-5" data-line-number="5"> <span class="dt">Just</span> (x,rest) <span class="ot">-></span> (<span class="kw">if</span> x <span class="fu">==</span> c <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span>) <span class="fu">+</span> countLetter c rest</a></code></pre></div>
|
||
<div class="sourceCode" id="cb314"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb314-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> countLetter <span class="ch">'t'</span> phrase</a>
|
||
<a class="sourceLine" id="cb314-2" data-line-number="2"><span class="dv">3</span></a></code></pre></div>
|
||
<h4 id="strictness-and-laziness"><span class="header-section-number">14.1.1.1</span> Strictness and Laziness</h4>
|
||
<p>Note that <code>Data.Text</code> implements the strict <code>Text</code> type. You need to use <code>Data.Text.Lazy</code> for the lazy variant. As mentioned earlier, one difference between these two types is that the strict type does not work for infinite strings:</p>
|
||
<div class="sourceCode" id="cb315"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb315-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> T.head (T.pack (repeat <span class="ch">'x'</span>))</a>
|
||
<a class="sourceLine" id="cb315-2" data-line-number="2"><span class="co">-- never returns</span></a>
|
||
<a class="sourceLine" id="cb315-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text.Lazy</span> <span class="kw">as</span> <span class="dt">LT</span></a>
|
||
<a class="sourceLine" id="cb315-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="dt">LT</span><span class="fu">.</span>head (<span class="dt">LT</span><span class="fu">.</span>pack (repeat <span class="ch">'x'</span>))</a>
|
||
<a class="sourceLine" id="cb315-5" data-line-number="5"><span class="ch">'x'</span></a></code></pre></div>
|
||
<p>Another practical problem that sometimes crops is that you can end up with a mismatch between strict and lazy <code>Text</code>s when using libraries. You can usually fix this by using <code>toStrict</code> or <code>fromStrict</code> as needed.</p>
|
||
<div class="sourceCode" id="cb316"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb316-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="kw">let</span> lazyPhrase <span class="fu">=</span> <span class="dt">LT</span><span class="fu">.</span>pack <span class="st">"brevity is the soul of wit"</span></a>
|
||
<a class="sourceLine" id="cb316-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="fu">:</span>t lazyPhrase</a>
|
||
<a class="sourceLine" id="cb316-3" data-line-number="3"><span class="ot">lazyPhrase ::</span> <span class="dt">LT</span><span class="fu">.</span><span class="dt">Text</span></a>
|
||
<a class="sourceLine" id="cb316-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="fu">:</span>t phrase</a>
|
||
<a class="sourceLine" id="cb316-5" data-line-number="5"><span class="ot">phrase ::</span> <span class="dt">T.Text</span></a>
|
||
<a class="sourceLine" id="cb316-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> lazyPhrase <span class="fu">==</span> phrase</a>
|
||
<a class="sourceLine" id="cb316-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb316-8" data-line-number="8"><span class="fu"><</span>interactive<span class="fu">>:</span> error<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb316-9" data-line-number="9"> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘<span class="dt">LT.Text</span>’</a>
|
||
<a class="sourceLine" id="cb316-10" data-line-number="10"> with actual <span class="kw">type</span> ‘<span class="dt">T.Text</span>’</a>
|
||
<a class="sourceLine" id="cb316-11" data-line-number="11"> <span class="dt">NB</span><span class="fu">:</span> ‘<span class="dt">T.Text</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.Text.Internal</span>’</a>
|
||
<a class="sourceLine" id="cb316-12" data-line-number="12"> ‘<span class="dt">LT.Text</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.Text.Internal.Lazy</span>’</a>
|
||
<a class="sourceLine" id="cb316-13" data-line-number="13"> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="fu">==</span>)’, namely ‘phrase’</a>
|
||
<a class="sourceLine" id="cb316-14" data-line-number="14"> <span class="dt">In</span> the expression<span class="fu">:</span> lazyPhrase <span class="fu">==</span> phrase</a>
|
||
<a class="sourceLine" id="cb316-15" data-line-number="15"> <span class="dt">In</span> an equation for ‘it’<span class="fu">:</span> it <span class="fu">=</span> lazyPhrase <span class="fu">==</span> phrase</a>
|
||
<a class="sourceLine" id="cb316-16" data-line-number="16"></a>
|
||
<a class="sourceLine" id="cb316-17" data-line-number="17"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="fu">:</span>t <span class="dt">LT</span><span class="fu">.</span>toStrict</a>
|
||
<a class="sourceLine" id="cb316-18" data-line-number="18"><span class="dt">LT</span><span class="fu">.</span><span class="ot">toStrict ::</span> <span class="dt">LT</span><span class="fu">.</span><span class="dt">Text</span> <span class="ot">-></span> <span class="dt">T.Text</span></a>
|
||
<a class="sourceLine" id="cb316-19" data-line-number="19"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="fu">:</span>t <span class="dt">LT</span><span class="fu">.</span>fromStrict</a>
|
||
<a class="sourceLine" id="cb316-20" data-line-number="20"><span class="dt">LT</span><span class="fu">.</span><span class="ot">fromStrict ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">LT</span><span class="fu">.</span><span class="dt">Text</span></a>
|
||
<a class="sourceLine" id="cb316-21" data-line-number="21"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">LT</span><span class="fu">></span> <span class="dt">LT</span><span class="fu">.</span>toStrict lazyPhrase <span class="fu">==</span> phrase</a>
|
||
<a class="sourceLine" id="cb316-22" data-line-number="22"><span class="dt">True</span></a></code></pre></div>
|
||
<h3 id="examples-with-bytestring"><span class="header-section-number">14.1.2</span> Examples with <code>ByteString</code></h3>
|
||
<p>We can walk through pretty much the same GHCi session using <code>ByteString</code> instead of <code>Text</code>. However, note how the <code>ByteString</code> is built up from <code>Word8</code> values and not <code>Char</code> values. A <code>Char</code> can represent an arbitrary unicode codepoint like for a character like <code>'Å'</code>, but a <code>Word8</code> represents a byte: a number from 0 to 255. Unfortunately and somewhat confusingly, <code>ByteString</code> values get printed like <code>String</code>s.</p>
|
||
<div class="sourceCode" id="cb317"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb317-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">import</span> <span class="dt">Data.Word</span></a>
|
||
<a class="sourceLine" id="cb317-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Data.Word</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString</span> <span class="kw">as</span> <span class="dt">B</span></a>
|
||
<a class="sourceLine" id="cb317-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="kw">let</span> binary <span class="fu">=</span> B.pack [<span class="dv">99</span>,<span class="dv">111</span>,<span class="dv">102</span>,<span class="dv">102</span>,<span class="dv">101</span>,<span class="dv">101</span>]</a>
|
||
<a class="sourceLine" id="cb317-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="fu">:</span>t binary</a>
|
||
<a class="sourceLine" id="cb317-5" data-line-number="5"><span class="ot">binary ::</span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb317-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="fu">:</span>t B.pack</a>
|
||
<a class="sourceLine" id="cb317-7" data-line-number="7">B.pack<span class="ot"> ::</span> [<span class="dt">Word8</span>] <span class="ot">-></span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb317-8" data-line-number="8"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> binary</a>
|
||
<a class="sourceLine" id="cb317-9" data-line-number="9"><span class="st">"coffee"</span></a>
|
||
<a class="sourceLine" id="cb317-10" data-line-number="10"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="fu">:</span>t B.length</a>
|
||
<a class="sourceLine" id="cb317-11" data-line-number="11">B.length<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb317-12" data-line-number="12"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> B.length binary</a>
|
||
<a class="sourceLine" id="cb317-13" data-line-number="13"><span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb317-14" data-line-number="14"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="fu">:</span>t B.head</a>
|
||
<a class="sourceLine" id="cb317-15" data-line-number="15">B.head<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">Word8</span></a>
|
||
<a class="sourceLine" id="cb317-16" data-line-number="16"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> B.head binary</a>
|
||
<a class="sourceLine" id="cb317-17" data-line-number="17"><span class="dv">99</span></a>
|
||
<a class="sourceLine" id="cb317-18" data-line-number="18"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> B.take <span class="dv">4</span> binary</a>
|
||
<a class="sourceLine" id="cb317-19" data-line-number="19"><span class="st">"coff"</span></a>
|
||
<a class="sourceLine" id="cb317-20" data-line-number="20"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="fu">:</span>t B.map</a>
|
||
<a class="sourceLine" id="cb317-21" data-line-number="21">B.map<span class="ot"> ::</span> (<span class="dt">Word8</span> <span class="ot">-></span> <span class="dt">Word8</span>) <span class="ot">-></span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb317-22" data-line-number="22"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> B.map (<span class="fu">+</span><span class="dv">1</span>) binary</a>
|
||
<a class="sourceLine" id="cb317-23" data-line-number="23"><span class="st">"dpggff"</span></a></code></pre></div>
|
||
<p>The same caveats apply to the differences between strict and lazy <code>ByteString</code> as for <code>Text</code>:</p>
|
||
<div class="sourceCode" id="cb318"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb318-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">B</span> <span class="dt">Data.Char</span><span class="fu">></span> B.head (B.pack (repeat <span class="dv">99</span>))</a>
|
||
<a class="sourceLine" id="cb318-2" data-line-number="2"><span class="co">-- never returns</span></a>
|
||
<a class="sourceLine" id="cb318-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy</span> <span class="kw">as</span> <span class="dt">LB</span></a>
|
||
<a class="sourceLine" id="cb318-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">LB</span><span class="fu">></span> LB.head (LB.pack (repeat <span class="dv">99</span>))</a>
|
||
<a class="sourceLine" id="cb318-5" data-line-number="5"><span class="dv">99</span></a>
|
||
<a class="sourceLine" id="cb318-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">LB</span><span class="fu">></span> binary <span class="fu">==</span> LB.pack [<span class="dv">99</span>]</a>
|
||
<a class="sourceLine" id="cb318-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb318-8" data-line-number="8"><span class="fu"><</span>interactive<span class="fu">>:</span> error<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb318-9" data-line-number="9"> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘<span class="dt">B.ByteString</span>’</a>
|
||
<a class="sourceLine" id="cb318-10" data-line-number="10"> with actual <span class="kw">type</span> ‘<span class="dt">LB.ByteString</span>’</a>
|
||
<a class="sourceLine" id="cb318-11" data-line-number="11"> <span class="dt">NB</span><span class="fu">:</span> ‘<span class="dt">LB.ByteString</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.ByteString.Lazy.Internal</span>’</a>
|
||
<a class="sourceLine" id="cb318-12" data-line-number="12"> ‘<span class="dt">B.ByteString</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.ByteString.Internal</span>’</a>
|
||
<a class="sourceLine" id="cb318-13" data-line-number="13"> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="fu">==</span>)’, namely ‘LB.pack [<span class="dv">99</span>]’</a>
|
||
<a class="sourceLine" id="cb318-14" data-line-number="14"> <span class="dt">In</span> the expression<span class="fu">:</span> binary <span class="fu">==</span> LB.pack [<span class="dv">99</span>]</a>
|
||
<a class="sourceLine" id="cb318-15" data-line-number="15"> <span class="dt">In</span> an equation for ‘it’<span class="fu">:</span> it <span class="fu">=</span> binary <span class="fu">==</span> LB.pack [<span class="dv">99</span>]</a>
|
||
<a class="sourceLine" id="cb318-16" data-line-number="16"></a>
|
||
<a class="sourceLine" id="cb318-17" data-line-number="17"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">LB</span><span class="fu">></span> <span class="fu">:</span>t LB.toStrict</a>
|
||
<a class="sourceLine" id="cb318-18" data-line-number="18">LB.toStrict<span class="ot"> ::</span> <span class="dt">LB.ByteString</span> <span class="ot">-></span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb318-19" data-line-number="19"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">LB</span><span class="fu">></span> <span class="fu">:</span>t LB.fromStrict</a>
|
||
<a class="sourceLine" id="cb318-20" data-line-number="20">LB.fromStrict<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">LB.ByteString</span></a>
|
||
<a class="sourceLine" id="cb318-21" data-line-number="21"><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">LB</span><span class="fu">></span> binary <span class="fu">==</span> LB.toStrict (LB.pack [<span class="dv">99</span>])</a>
|
||
<a class="sourceLine" id="cb318-22" data-line-number="22"><span class="dt">False</span></a></code></pre></div>
|
||
<h3 id="sidenote-encodings"><span class="header-section-number">14.1.3</span> Sidenote: Encodings</h3>
|
||
<p>You might be wondering why on earth do we have both Text and ByteString. The difference is subtle but real. When we operate on <code>Text</code> we operate character by character, regardless of what those characters are and how they are encoded. When we operate on <code>ByteString</code> we operate on bytes, regardless of what those bytes represent.</p>
|
||
<p>Characters, numbers, and data structures are abstractions that help us humans to deal with complex programming tasks. The computer memory is essentially just an enormous sequence of bytes. The machine doesn’t care how we interpret those bytes. The essential difference between <code>Text</code> and <code>ByteString</code> is the way how the bytes are grouped and interpreted.</p>
|
||
<p>To illustrate this difference, we’ll look at the <a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8 text encoding</a>. A text encoding is a method for representing <em>characters</em> as <em>bytes</em>. UTF-8 can represent all the millions of characters defined by <a href="https://en.wikipedia.org/wiki/Unicode">Unicode</a>. Because bytes can only store values from 0 to 255, this means that a character can get encoded into multiple bytes. The bits and bytes of the UTF-8 string “Ha∫keλ!” can be interpreted in various ways:</p>
|
||
<p><img src="img/string.svg" /></p>
|
||
<p>(If you see different characters in the picture and in “Ha∫keλ!”, it means that your browser is either interpreting the encoding incorrectly or the font you’re usign doesn’t support all of the characters.)</p>
|
||
<p>If we read the same stream of bits using a different encoding, we’ll see other characters. For example the string above would be interpreted as “Haâ«keλ!” using the <a href="https://en.wikipedia.org/wiki/Latin-1">Latin-1 text encoding</a>.</p>
|
||
<p>By the way, when dealing with raw binary data, it’s often convenient to use the hexadecimal number system which uses a single symbol <code>0</code>, <code>1</code>, …, <code>9</code>, <code>A</code>, <code>B</code>, …, <code>F</code> to represent all of the sixteen possible combinations of four bits. We don’t need hexadecimal in this course but you can check out <a href="https://en.wikipedia.org/wiki/Hexadecimal">Wikipedia</a> if you’re interested in learning more about hexadecimal.</p>
|
||
<p>We can explore the same example using code. The function <code>Data.Text.Encoding.encodeUtf8 :: Text -> ByteString</code> encodes the characters in a Text into bytes in a ByteString using UTF-8.</p>
|
||
<div class="sourceCode" id="cb319"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb319-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></a>
|
||
<a class="sourceLine" id="cb319-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString</span> <span class="kw">as</span> <span class="dt">B</span></a>
|
||
<a class="sourceLine" id="cb319-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="fu">></span> T.length (T.pack <span class="st">"haskell"</span>)</a>
|
||
<a class="sourceLine" id="cb319-4" data-line-number="4"><span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb319-5" data-line-number="5"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="fu">></span> T.length (T.pack <span class="st">"Ha∫keλ!"</span>)</a>
|
||
<a class="sourceLine" id="cb319-6" data-line-number="6"><span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb319-7" data-line-number="7"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="fu">></span> <span class="kw">import</span> <span class="dt">Data.Text.Encoding</span></a>
|
||
<a class="sourceLine" id="cb319-8" data-line-number="8"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="fu">></span> encodeUtf8 (T.pack <span class="st">"haskell"</span>)</a>
|
||
<a class="sourceLine" id="cb319-9" data-line-number="9"><span class="st">"haskell"</span></a>
|
||
<a class="sourceLine" id="cb319-10" data-line-number="10"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="fu">></span> encodeUtf8 (T.pack <span class="st">"Ha∫keλ!"</span>)</a>
|
||
<a class="sourceLine" id="cb319-11" data-line-number="11"><span class="st">"Ha\226\136\171ke\206\187!"</span></a>
|
||
<a class="sourceLine" id="cb319-12" data-line-number="12"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="fu">></span> B.length (encodeUtf8 (T.pack <span class="st">"haskell"</span>))</a>
|
||
<a class="sourceLine" id="cb319-13" data-line-number="13"><span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb319-14" data-line-number="14"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="fu">></span> B.length (encodeUtf8 (T.pack <span class="st">"Ha∫keλ!"</span>))</a>
|
||
<a class="sourceLine" id="cb319-15" data-line-number="15"><span class="dv">10</span></a></code></pre></div>
|
||
<p>If we are processing <a href="https://en.wikipedia.org/wiki/ASCII">ASCII text</a>, that is, characters that can be represented using single bytes, we can use <code>Text</code> and <code>ByteString</code> interchangeably. There are namespaces <code>Data.ByteString.Char8</code> and <code>Data.ByteString.Lazy.Char8</code> that offer functions that operate on <code>ByteString</code>s using <code>Char</code> values instead of <code>Word8</code>. However, care must be taken to make sure all the characters really are plain ASCII characters, or surprising things will happen.</p>
|
||
<div class="sourceCode" id="cb320"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb320-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Char8</span> <span class="kw">as</span> <span class="dt">B8</span></a>
|
||
<a class="sourceLine" id="cb320-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> B8.pack <span class="st">"abc"</span></a>
|
||
<a class="sourceLine" id="cb320-3" data-line-number="3"><span class="st">"abc"</span></a>
|
||
<a class="sourceLine" id="cb320-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> <span class="fu">:</span>t B8.pack</a>
|
||
<a class="sourceLine" id="cb320-5" data-line-number="5">B8.pack<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb320-6" data-line-number="6"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> <span class="fu">:</span>t B.pack</a>
|
||
<a class="sourceLine" id="cb320-7" data-line-number="7">B.pack<span class="ot"> ::</span> [<span class="dt">Word8</span>] <span class="ot">-></span> <span class="dt">B.ByteString</span></a>
|
||
<a class="sourceLine" id="cb320-8" data-line-number="8"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> B8.cons <span class="ch">'a'</span> (B8.pack <span class="st">"bc"</span>)</a>
|
||
<a class="sourceLine" id="cb320-9" data-line-number="9"><span class="st">"abc"</span></a>
|
||
<a class="sourceLine" id="cb320-10" data-line-number="10"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> putStrLn (B8.unpack (B8.pack <span class="st">"€λ훈"</span>)) <span class="co">-- non-ASCII characters get truncated</span></a>
|
||
<a class="sourceLine" id="cb320-11" data-line-number="11">¬»È</a>
|
||
<a class="sourceLine" id="cb320-12" data-line-number="12"><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="fu">></span> putStrLn (T.unpack (T.pack <span class="st">"€λ훈"</span>))</a>
|
||
<a class="sourceLine" id="cb320-13" data-line-number="13">€λ훈</a></code></pre></div>
|
||
<h2 id="monads-recap"><span class="header-section-number">14.2</span> Monads: Recap</h2>
|
||
<p>The next libraries we’ll look at work inside the IO monad. Here’s a short recap of what we learned about monads in the last lecture.</p>
|
||
<ul>
|
||
<li>When <code>M</code> is a monad, values of type <code>M X</code> are <em>operations</em> that can be <em>executed</em> to <em>produce</em> a value of type <code>X</code>.</li>
|
||
<li>Monadic operations can be implemented using
|
||
<ul>
|
||
<li>the methods of the <code>Monad</code> type class (<code>return</code>, <code>>>=</code>, <code>>></code>),</li>
|
||
<li><code>do</code>-notation,</li>
|
||
<li>and library functions like <code>mapM</code>.</li>
|
||
</ul></li>
|
||
<li>Unlike in other languages, <code>return</code> is not a keyword and does not cause an operation to stop executing. Instead, <code>return x</code> <em>is the operation that always produces x and does nothing else</em>.</li>
|
||
<li>This is what <code>do</code>-notation looks like:</li>
|
||
</ul>
|
||
<div class="sourceCode" id="cb321"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb321-1" data-line-number="1">foo y <span class="fu">=</span> <span class="kw">do</span></a>
|
||
<a class="sourceLine" id="cb321-2" data-line-number="2"> operation1 <span class="co">-- run an operation</span></a>
|
||
<a class="sourceLine" id="cb321-3" data-line-number="3"> val <span class="ot"><-</span> operation2 <span class="co">-- run an operation and keep the produced value</span></a>
|
||
<a class="sourceLine" id="cb321-4" data-line-number="4"> operation3 val y <span class="co">-- run an operation with parameters</span></a>
|
||
<a class="sourceLine" id="cb321-5" data-line-number="5"> mapM_ (\x <span class="ot">-></span> operation4 val x) things <span class="co">-- use a generic monad operation and a lambda</span></a>
|
||
<a class="sourceLine" id="cb321-6" data-line-number="6"> operation5 val <span class="co">-- the final line of the do decides which value the whole block produces</span></a></code></pre></div>
|
||
<!-- TODO more? -->
|
||
<h2 id="writing-a-http-server-wai-and-warp"><span class="header-section-number">14.3</span> Writing a HTTP Server: WAI and Warp</h2>
|
||
<p>Sometimes it feels like everything in the world happens over <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol">HTTP</a> and <a href="https://en.wikipedia.org/wiki/Web_API">Web Apis</a>. Your web browser, your smartphone apps, <a href="https://developer.nordeaopenbanking.com/">your bank</a>, <a href="https://tools.ietf.org/html/rfc2324">your coffee pot</a>, <a href="https://support.ring.com/hc/en-us/articles/205385394-The-Protocols-and-Ports-Used-by-Ring-Devices">and even your doorbell</a>, all talk to servers using the HTTP protocol.</p>
|
||
<p>Let’s look at how we can set up a simple HTTP server in Haskell. The standard low level components for this are called <a href="https://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html">WAI</a> and <a href="http://hackage.haskell.org/package/warp-3.3.13">Warp</a>. WAI, the Web Application Interface gives us a way to define how HTTP requests are handled. Warp is a simple HTTP server that runs the logic we have defined using WAI. That probably sounds a bit abstract right now, but a simple example will help.</p>
|
||
<p>The file <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/HelloServer.hs"><code>exercises/Examples/HelloServer.hs</code></a> implements a HTTP server that always responds with “Hello World!”. You can try it out by going to the <code>exercises/Examples</code> directory and running it with <code>stack runhaskell HelloServer.hs</code>. After that you can visit <a href="http://localhost:3421" class="uri">http://localhost:3421</a> in your browser to see the response from the server.</p>
|
||
<div class="sourceCode" id="cb322"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb322-1" data-line-number="1"><span class="kw">module</span> <span class="dt">Examples.HelloServer</span> <span class="kw">where</span></a>
|
||
<a class="sourceLine" id="cb322-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb322-3" data-line-number="3"><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.ByteString.Lazy.Char8</span> <span class="kw">as</span> <span class="dt">LB</span></a>
|
||
<a class="sourceLine" id="cb322-4" data-line-number="4"><span class="kw">import</span> <span class="dt">Network.HTTP.Types.Status</span> (status200)</a>
|
||
<a class="sourceLine" id="cb322-5" data-line-number="5"><span class="kw">import</span> <span class="dt">Network.Wai</span> (<span class="dt">Application</span>, responseLBS)</a>
|
||
<a class="sourceLine" id="cb322-6" data-line-number="6"><span class="kw">import</span> <span class="dt">Network.Wai.Handler.Warp</span> (run)</a>
|
||
<a class="sourceLine" id="cb322-7" data-line-number="7"></a>
|
||
<a class="sourceLine" id="cb322-8" data-line-number="8"><span class="ot">port ::</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb322-9" data-line-number="9">port <span class="fu">=</span> <span class="dv">3421</span></a>
|
||
<a class="sourceLine" id="cb322-10" data-line-number="10"></a>
|
||
<a class="sourceLine" id="cb322-11" data-line-number="11"><span class="ot">main ::</span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb322-12" data-line-number="12">main <span class="fu">=</span> run port application</a>
|
||
<a class="sourceLine" id="cb322-13" data-line-number="13"></a>
|
||
<a class="sourceLine" id="cb322-14" data-line-number="14"><span class="co">-- type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived</span></a>
|
||
<a class="sourceLine" id="cb322-15" data-line-number="15"><span class="ot">server ::</span> <span class="dt">Application</span></a>
|
||
<a class="sourceLine" id="cb322-16" data-line-number="16">server request respond <span class="fu">=</span></a>
|
||
<a class="sourceLine" id="cb322-17" data-line-number="17"> respond (responseLBS status200 [] (LB.pack <span class="st">"Hello World!"</span>))</a></code></pre></div>
|
||
<p>Let’s look at the types in this example. There’s a lot going on here. First off, <code>Application</code> is a <em>type alias</em> for a thing that implements the logic of a web server. The <a href="http://hackage.haskell.org/package/warp-3.3.13/docs/Network-Wai-Handler-Warp.html#v:run"><code>run</code> function from Warp</a> can run <code>Application</code>s:</p>
|
||
<div class="sourceCode" id="cb323"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb323-1" data-line-number="1"><span class="ot">run ::</span> <span class="dt">Port</span> <span class="ot">-></span> <span class="dt">Application</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb323-2" data-line-number="2"><span class="kw">type</span> <span class="dt">Application</span> <span class="fu">=</span> <span class="dt">Request</span> <span class="ot">-></span> (<span class="dt">Response</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">ResponseReceived</span>) <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">ResponseReceived</span></a></code></pre></div>
|
||
<p>We’ll talk about what <code>Request</code> and <code>Response</code> are soon, but from this type we can see that an <code>Application</code> is an IO operation that takes as arguments a request of type <code>Request</code>, and an IO operation <code>respond :: Response -> IO ResponseReceived</code>. Arguments like <code>respond</code> are called <em>callbacks</em> in many contexts. They allow us to call back to the library who called the application. The <code>Application</code> operation has to produce the same special <code>ResponseReceived</code> type that <code>respond</code>. You can think of this type as a token proving that <code>respond</code> was called by the <code>Application</code>.</p>
|
||
<p>That might sound intimidating: but looking at the code things are relatively simple: our <code>server</code> is an <code>Application</code> and takes two parameters: <code>request</code> and <code>respond</code>.</p>
|
||
<p>WAI uses lots of types like <code>Port</code>, <code>Request</code>, <code>Response</code>, <code>Status</code> to represent HTTP concepts. It’s useful to look these up in the documentation when you bump into them. For example <a href="http://hackage.haskell.org/package/warp-3.3.13/docs/Network-Wai-Handler-Warp.html#t:Port"><code>Port</code> is just an alias for <code>Int</code></a>. As another example, we can see the <a href="https://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html#v:responseLBS"><code>responseLBS</code> function</a> has the type</p>
|
||
<div class="sourceCode" id="cb324"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb324-1" data-line-number="1"><span class="ot">responseLBS ::</span> <span class="dt">Status</span> <span class="ot">-></span> <span class="dt">ResponseHeaders</span> <span class="ot">-></span> <span class="dt">ByteString</span> <span class="ot">-></span> <span class="dt">Response</span></a></code></pre></div>
|
||
<p>where <a href="https://hackage.haskell.org/package/http-types-0.12.3/docs/Network-HTTP-Types-Status.html#t:Status"><code>Status</code> is defined in <code>Network.HTTP.Types.Status</code></a>, <a href="https://hackage.haskell.org/package/http-types-0.12.3/docs/Network-HTTP-Types-Header.html#t:ResponseHeaders"><code>ResponseHeaders</code> is a type alias for <code>[Header]</code> from <code>Network.HTTP.Types.Header</code></a>, <code>ByteString</code> is a lazy <code>ByteString</code>, and the result type <a href="https://hackage.haskell.org/package/wai-3.2.2.1/docs/Network-Wai.html#t:Response"><code>Response</code> is defined by <code>Network.WAI</code></a>.</p>
|
||
<p>Finally, note that we take a shortcut and use the function <code>Data.ByteString.Lazy.Char8.pack</code> to convert a <code>String</code> into a <code>ByteString</code>. This only works for ASCII text.</p>
|
||
<p>A web server that always responds with the same text isn’t that interesting. Let’s look at how we can give different responses to different requests next. There are many parts in a HTTP request, but for this lecture we’re going to focus on the <em>path</em>. In a URL like <code>http://example.com/abcd/ef/file</code>, the <code>/abcd/ef/file</code> part is the path. WAI has the function</p>
|
||
<div class="sourceCode" id="cb325"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb325-1" data-line-number="1"><span class="ot">pathInfo ::</span> <span class="dt">Request</span> <span class="ot">-></span> [<span class="dt">Text</span>]</a></code></pre></div>
|
||
<p>This gives us the path of the requested URL, split at the <code>/</code> characters.</p>
|
||
<p>The file <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/PathServer.hs"><code>exercises/Examples/PathServer.hs</code></a> implements a web server that has three different pages:</p>
|
||
<ul>
|
||
<li><a href="http://localhost:3421/source" class="uri">http://localhost:3421/source</a> is the source of the application itself, read from the file system</li>
|
||
<li><a href="http://localhost:3421/secret/file" class="uri">http://localhost:3421/secret/file</a> is a secret string</li>
|
||
<li><a href="http://localhost:3421/anything/else" class="uri">http://localhost:3421/anything/else</a> - for all other paths, a “Not found: anything/else” text is shown</li>
|
||
</ul>
|
||
<p>As before, you can run the server by going into the <code>exercises/Examples</code> directory, and running <code>stack runhaskell PathServer.hs</code>.</p>
|
||
<!-- TODO walk through the code of the PathServer? -->
|
||
<h2 id="working-with-a-database-sqlite-simple"><span class="header-section-number">14.4</span> Working With a Database: sqlite-simple</h2>
|
||
<p>After implementing a HTTP server we can participate in the global graph of applications talking to each other that’s called the internet. But what use is talking if we can’t remember? A real application needs to be able to <em>persist data</em> even when it is restarted. A common way to accomplish this is to use a database.</p>
|
||
<p>There are many different kinds of databases, but arguably the most widely used simple database is <a href="https://www.sqlite.org/index.html">SQLite</a>. SQLite is a library that lets you store data in a file and process it using <a href="">SQL, the Structured Query Language</a>. With SQLite there is no need to run a separate database server a la <a href="https://www.postgresql.org/">PostgreSQL</a> or <a href="https://www.mysql.com/">MySQL</a>.</p>
|
||
<p>In case you’re not familiar with SQL, don’t worry, you won’t need to write any queries of your own in the exercises. If you’d like to learn a bit of SQL now, there are lots of tutorials on the web. See <a href="https://www.w3schools.com/sql/">W3Schools</a>, <a href="https://sqlzoo.net/">SQL Zoo</a> or <a href="https://www.codecademy.com/learn/learn-sql">Codecademy</a>.</p>
|
||
<p>There are many libraries for Haskell for using SQLite, but we’ll look at one called <a href="https://hackage.haskell.org/package/sqlite-simple-0.4.18.0">sqlite-simple</a> here. Let’s explore the library in GHCi for a bit.</p>
|
||
<p>All the functions live inside <code>Database.SQLite.Simple</code>. You can open a database by giving a filename to <code>open</code>, which is an IO operation that produces a <code>Connection</code>.</p>
|
||
<div class="sourceCode" id="cb326"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb326-1" data-line-number="1"><span class="dt">Prelude</span><span class="fu">></span> <span class="kw">import</span> <span class="dt">Database.SQLite.Simple</span></a>
|
||
<a class="sourceLine" id="cb326-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="fu">></span> <span class="fu">:</span>t open</a>
|
||
<a class="sourceLine" id="cb326-3" data-line-number="3"><span class="ot">open ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Connection</span></a>
|
||
<a class="sourceLine" id="cb326-4" data-line-number="4"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="fu">></span> db <span class="ot"><-</span> open <span class="st">"example.sqlite"</span></a></code></pre></div>
|
||
<p>To run an SQL query you can use IO operation <code>query_</code>, which takes a <code>Connection</code> and a <code>Query</code>, and produces a list of results. The <code>Query</code> type is just a simple <code>newtype</code> around <code>Text</code>. The result type of <code>query_</code>is polymorphic: you can read any type that satisfies the <code>FromRow</code> type class from the database. If this feels confusing, compare it to the type of <code>read</code>: <code>Read a => String -> a</code>. The <code>FromRow</code> class is like <code>Read</code> for this database: it represents types that can be read out of the database. Anyway, let’s read the number <code>1</code> from the database:</p>
|
||
<div class="sourceCode" id="cb327"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb327-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="fu">></span> <span class="fu">:</span>t query_</a>
|
||
<a class="sourceLine" id="cb327-2" data-line-number="2"><span class="ot">query_ ::</span> <span class="dt">FromRow</span> r <span class="ot">=></span> <span class="dt">Connection</span> <span class="ot">-></span> <span class="dt">Query</span> <span class="ot">-></span> <span class="dt">IO</span> [r]</a>
|
||
<a class="sourceLine" id="cb327-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="fu">></span> <span class="fu">:</span>info <span class="dt">Query</span></a>
|
||
<a class="sourceLine" id="cb327-4" data-line-number="4"><span class="kw">newtype</span> <span class="dt">Query</span> <span class="fu">=</span> <span class="dt">Query</span> {<span class="ot">fromQuery ::</span> <span class="dt">Data.Text.Internal.Text</span>}</a>
|
||
<a class="sourceLine" id="cb327-5" data-line-number="5"> <span class="co">-- Defined in ‘Database.SQLite.Simple.Types’</span></a>
|
||
<a class="sourceLine" id="cb327-6" data-line-number="6"> <span class="co">-- ... rest of output omitted</span></a>
|
||
<a class="sourceLine" id="cb327-7" data-line-number="7"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="fu">></span> <span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Text</span> <span class="kw">as</span> <span class="dt">T</span></a>
|
||
<a class="sourceLine" id="cb327-8" data-line-number="8"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">let</span> q <span class="fu">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT 1;"</span>)</a>
|
||
<a class="sourceLine" id="cb327-9" data-line-number="9"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> res <span class="ot"><-</span> query_ db<span class="ot"> q ::</span> <span class="dt">IO</span> [[<span class="dt">Int</span>]]</a>
|
||
<a class="sourceLine" id="cb327-10" data-line-number="10"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> res</a>
|
||
<a class="sourceLine" id="cb327-11" data-line-number="11">[[<span class="dv">1</span>]]</a></code></pre></div>
|
||
<p>By the way, all of these initial examples use simple <code>SELECT x, y, z;</code> queries that just return constant data. We’ll worry about actual tables in the database later.</p>
|
||
<p>Without the type signature, we get an error from GHCi, which can’t decide which type we want to read out from the database:</p>
|
||
<div class="sourceCode" id="cb328"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb328-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> res <span class="ot"><-</span> query_ db q</a>
|
||
<a class="sourceLine" id="cb328-2" data-line-number="2"></a>
|
||
<a class="sourceLine" id="cb328-3" data-line-number="3"><span class="fu"><</span>interactive<span class="fu">>:</span><span class="dv">17</span><span class="fu">:</span><span class="dv">8</span><span class="fu">:</span> error<span class="fu">:</span></a>
|
||
<a class="sourceLine" id="cb328-4" data-line-number="4"> • <span class="dt">Ambiguous</span> <span class="kw">type</span> variable ‘r0’ arising from a use <span class="kw">of</span> ‘query_’</a>
|
||
<a class="sourceLine" id="cb328-5" data-line-number="5"> prevents the constraint ‘(<span class="dt">FromRow</span> r0)’ from being solved<span class="fu">.</span></a>
|
||
<a class="sourceLine" id="cb328-6" data-line-number="6"> <span class="dt">Probable</span> fix<span class="fu">:</span> use a <span class="kw">type</span> annotation to specify what ‘r0’ should be<span class="fu">.</span></a>
|
||
<a class="sourceLine" id="cb328-7" data-line-number="7"> <span class="co">-- rest of error omitted</span></a></code></pre></div>
|
||
<p>Before we go on, let’s have a closer look at <code>FromRow</code>. If you’ve bumped into SQL before, you know that an SQL query returns a number of <em>rows</em>, and each row consists of a number of <em>values</em> (also called <em>columns</em>). To be able to interpret the result of an SQL query into Haskell data, we need a way to interpret these values and rows. Thus sqlite-simple defines two classes, <code>FromField</code> and <code>FromRow</code>, and a bunch of instances like the following. (You can find these instances from <a href="https://hackage.haskell.org/package/sqlite-simple-0.4.18.0/docs/Database-SQLite-Simple.html#t:FromRow">the docs</a> or by asking GHCi with <code>:info FromRow</code> etc.)</p>
|
||
<div class="sourceCode" id="cb329"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb329-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb329-2" data-line-number="2"><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb329-3" data-line-number="3"><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb329-4" data-line-number="4"><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Text</span></a>
|
||
<a class="sourceLine" id="cb329-5" data-line-number="5"><span class="kw">instance</span> <span class="dt">FromField</span> a <span class="ot">=></span> <span class="dt">FromRow</span> [a]</a>
|
||
<a class="sourceLine" id="cb329-6" data-line-number="6"><span class="kw">instance</span> (<span class="dt">FromField</span> a, <span class="dt">FromField</span> b) <span class="ot">=></span> <span class="dt">FromRow</span> (a,b)</a>
|
||
<a class="sourceLine" id="cb329-7" data-line-number="7"><span class="kw">instance</span> (<span class="dt">FromField</span> a, <span class="dt">FromField</span> b, <span class="dt">FromField</span> c) <span class="ot">=></span> <span class="dt">FromRow</span> (a,b,c)</a></code></pre></div>
|
||
<p>In essence, basic Haskell datatypes fulfill the <code>FromField</code> class, and various Haskell collections fulfill the <code>FromRow</code> class. Our earlier example was using the <code>FromRow [a]</code> and <code>FromField Int</code> instances to get a <code>[[Int]]</code> out of <code>query_</code>. Here’s a simple query that uses some other datatypes:</p>
|
||
<div class="sourceCode" id="cb330"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb330-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">let</span> q <span class="fu">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT 1, true, 'string';"</span>)</a>
|
||
<a class="sourceLine" id="cb330-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> query_ db<span class="ot"> q ::</span> <span class="dt">IO</span> [(<span class="dt">Int</span>,<span class="dt">Bool</span>,<span class="dt">String</span>)]</a>
|
||
<a class="sourceLine" id="cb330-3" data-line-number="3">[(<span class="dv">1</span>,<span class="dt">True</span>,<span class="st">"string"</span>)]</a></code></pre></div>
|
||
<p>What happens if the SQL and Haskell types don’t match? Well, you get a runtime error, just like if you try to invoke <code>read "True" :: Int</code>.</p>
|
||
<div class="sourceCode" id="cb331"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb331-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> query_ db<span class="ot"> q ::</span> <span class="dt">IO</span> [(<span class="dt">Int</span>,<span class="dt">Int</span>,<span class="dt">Int</span>)]</a>
|
||
<a class="sourceLine" id="cb331-2" data-line-number="2"><span class="fu">***</span> <span class="dt">Exception</span><span class="fu">:</span> <span class="dt">ConversionFailed</span> {errSQLType <span class="fu">=</span> <span class="st">"TEXT"</span>, errHaskellType <span class="fu">=</span> <span class="st">"Int"</span>, errMessage <span class="fu">=</span> <span class="st">"need an int"</span>}</a></code></pre></div>
|
||
<p>To mirror the <code>FromRow</code> and <code>FromField</code> classes, sqlite-simple also defines the <code>ToRow</code> and <code>ToField</code> classes for writing into the database. Here’s the type of the <code>query</code> function, which allows us to use <em>parameterized queries</em>.</p>
|
||
<div class="sourceCode" id="cb332"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb332-1" data-line-number="1"><span class="ot">query ::</span> (<span class="dt">ToRow</span> q, <span class="dt">FromRow</span> r) <span class="ot">=></span> <span class="dt">Connection</span> <span class="ot">-></span> <span class="dt">Query</span> <span class="ot">-></span> q <span class="ot">-></span> <span class="dt">IO</span> [r]</a></code></pre></div>
|
||
<p>And here are some instances for <code>ToRow</code> and <code>ToField</code>:</p>
|
||
<div class="sourceCode" id="cb333"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb333-1" data-line-number="1"><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb333-2" data-line-number="2"><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Bool</span></a>
|
||
<a class="sourceLine" id="cb333-3" data-line-number="3"><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">String</span></a>
|
||
<a class="sourceLine" id="cb333-4" data-line-number="4"><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Text</span></a>
|
||
<a class="sourceLine" id="cb333-5" data-line-number="5"><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Int</span></a>
|
||
<a class="sourceLine" id="cb333-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb333-7" data-line-number="7"><span class="kw">instance</span> <span class="dt">ToField</span> a <span class="ot">=></span> <span class="dt">ToRow</span> [a]</a>
|
||
<a class="sourceLine" id="cb333-8" data-line-number="8"><span class="kw">instance</span> (<span class="dt">ToField</span> a, <span class="dt">ToField</span> b) <span class="ot">=></span> <span class="dt">ToRow</span> (a, b)</a>
|
||
<a class="sourceLine" id="cb333-9" data-line-number="9"><span class="kw">instance</span> (<span class="dt">ToField</span> a, <span class="dt">ToField</span> b, <span class="dt">ToField</span> c) <span class="ot">=></span> <span class="dt">ToRow</span> (a, b, c)</a></code></pre></div>
|
||
<!-- instance ToField a => ToField (Maybe a) -- TODO talk about sql null -->
|
||
<p>Parameterized queries use a <code>?</code> character to denote slots where parameters can be passed in. Here’s a simple example:</p>
|
||
<div class="sourceCode" id="cb334"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb334-1" data-line-number="1"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">let</span> input <span class="fu">=</span> (<span class="dv">1</span>,<span class="st">"hello"</span>)<span class="ot"> ::</span> (<span class="dt">Int</span>,<span class="dt">String</span>)</a>
|
||
<a class="sourceLine" id="cb334-2" data-line-number="2"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> <span class="kw">let</span> parameterized <span class="fu">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT ?+1, true, ?;"</span>)</a>
|
||
<a class="sourceLine" id="cb334-3" data-line-number="3"><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="fu">></span> query db parameterized<span class="ot"> input ::</span> <span class="dt">IO</span> [(<span class="dt">Int</span>,<span class="dt">Bool</span>,<span class="dt">String</span>)]</a>
|
||
<a class="sourceLine" id="cb334-4" data-line-number="4">[(<span class="dv">2</span>,<span class="dt">True</span>,<span class="st">"hello"</span>)]</a></code></pre></div>
|
||
<p>That’s pretty much all you need to know about sqlite-simple: <code>open</code>, <code>query_</code>, <code>query</code>, <code>FromRow</code>, <code>ToRow</code>. Oh right, one more thing. There are the functions <code>execute</code> and <code>execute_</code> if you don’t need the result of the query. They’re useful for inserting things into the database, for example.</p>
|
||
<div class="sourceCode" id="cb335"><pre class="sourceCode haskell"><code class="sourceCode haskell"><a class="sourceLine" id="cb335-1" data-line-number="1"><span class="ot">execute_ ::</span> <span class="dt">Connection</span> <span class="ot">-></span> <span class="dt">Query</span> <span class="ot">-></span> <span class="dt">IO</span> ()</a>
|
||
<a class="sourceLine" id="cb335-2" data-line-number="2"><span class="ot">execute ::</span> <span class="dt">ToRow</span> q <span class="ot">=></span> <span class="dt">Connection</span> <span class="ot">-></span> <span class="dt">Query</span> <span class="ot">-></span> q <span class="ot">-></span> <span class="dt">IO</span> ()</a></code></pre></div>
|
||
<p>You’ll find an example program that uses sqlite-simple to maintain a phone book under <a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/Phonebook.hs"><code>exercises/Examples/Phonebook.hs</code></a>. The program keeps the phonebook in a file called <code>phonebook.db</code> and works like this (run from the <code>exercises/Examples</code> directory in the course repository):</p>
|
||
<pre><code>$ stack runhaskell Phonebook.hs
|
||
(a)dd or (q)uery?
|
||
a
|
||
Name?
|
||
bob
|
||
Phone?
|
||
1234
|
||
$ stack runhaskell Phonebook.hs
|
||
(a)dd or (q)uery?
|
||
a
|
||
Name?
|
||
bob
|
||
Phone?
|
||
5678
|
||
$ stack runhaskell Phonebook.hs
|
||
(a)dd or (q)uery?
|
||
a
|
||
Name?
|
||
samantha
|
||
Phone?
|
||
1357
|
||
$ stack runhaskell Phonebook.hs
|
||
(a)dd or (q)uery?
|
||
q
|
||
Name?
|
||
bob
|
||
2 numbers:
|
||
["1234"]
|
||
["5678"]</code></pre>
|
||
<p>PS. If you’re devastated by the lack of compile-time type checking for SQL queries, you can have a look at some of the more advanced SQL libraries for Haskell like <a href="https://haskell-beam.github.io/beam/">Beam</a> or <a href="https://hackage.haskell.org/package/opaleye">Opaleye</a>. This course is using sqlite-simple for simplicity and to avoid dwelling on the details of SQL too much.</p>
|
||
<!-- ## TODO Quiz: this set isn't that well suited for quiz questions -->
|
||
<h2 id="exercises-5"><span class="header-section-number">14.5</span> Exercises</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set14a.hs">Set14a</a>: Text & ByteString</li>
|
||
<li><a href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set14b.hs">Set14b</a>: HTTP & SQLite</li>
|
||
<li><a href="https://forms.gle/soVtMeGBxSo6u5zp6">Remember to give feedback!</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|