mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
7049 lines
801 KiB
HTML
7049 lines
801 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">
|
||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||
pre > code.sourceCode > span { line-height: 1.25; }
|
||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||
.sourceCode { overflow: visible; }
|
||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
pre > code.sourceCode { white-space: pre-wrap; }
|
||
pre > code.sourceCode > span { display: inline-block; text-indent: -5em; padding-left: 5em; }
|
||
}
|
||
pre.numberSource code
|
||
{ counter-reset: source-line 0; }
|
||
pre.numberSource code > span
|
||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||
pre.numberSource code > span > a:first-child::before
|
||
{ content: counter(source-line);
|
||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||
border: none; display: inline-block;
|
||
-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 {
|
||
pre > code.sourceCode > span > a:first-child::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 { color: #008000; } /* 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 { color: #008000; font-weight: bold; } /* 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"
|
||
id="toc-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" id="toc-types"><span
|
||
class="toc-section-number">9.1</span> Types</a></li>
|
||
<li><a href="#functions" id="toc-functions"><span
|
||
class="toc-section-number">9.2</span> Functions</a></li>
|
||
<li><a href="#functional-programming"
|
||
id="toc-functional-programming"><span
|
||
class="toc-section-number">9.3</span> Functional Programming</a></li>
|
||
<li><a href="#recursion" id="toc-recursion"><span
|
||
class="toc-section-number">9.4</span> Recursion</a></li>
|
||
<li><a href="#type-classes" id="toc-type-classes"><span
|
||
class="toc-section-number">9.5</span> Type Classes</a></li>
|
||
<li><a href="#quiz" id="toc-quiz"><span
|
||
class="toc-section-number">9.6</span> Quiz</a></li>
|
||
<li><a href="#working-on-the-exercises"
|
||
id="toc-working-on-the-exercises"><span
|
||
class="toc-section-number">9.7</span> Working on the Exercises</a></li>
|
||
<li><a href="#exercises" id="toc-exercises"><span
|
||
class="toc-section-number">9.8</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-10-reductionism"
|
||
id="toc-lecture-10-reductionism"><span
|
||
class="toc-section-number">10</span> Lecture 10: Reductionism</a>
|
||
<ul>
|
||
<li><a href="#laziness-purity" id="toc-laziness-purity"><span
|
||
class="toc-section-number">10.1</span> Laziness & Purity</a></li>
|
||
<li><a href="#equational-reasoning" id="toc-equational-reasoning"><span
|
||
class="toc-section-number">10.2</span> Equational Reasoning</a></li>
|
||
<li><a href="#infinite-lists" id="toc-infinite-lists"><span
|
||
class="toc-section-number">10.3</span> Infinite Lists</a></li>
|
||
<li><a href="#how-does-haskell-work"
|
||
id="toc-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"
|
||
id="toc-working-with-infinite-lists"><span
|
||
class="toc-section-number">10.5</span> Working with Infinite
|
||
Lists</a></li>
|
||
<li><a href="#interlude-adding-strictness"
|
||
id="toc-interlude-adding-strictness"><span
|
||
class="toc-section-number">10.6</span> Interlude: Adding
|
||
Strictness</a></li>
|
||
<li><a href="#newtype-declarations" id="toc-newtype-declarations"><span
|
||
class="toc-section-number">10.7</span> Newtype Declarations</a></li>
|
||
<li><a href="#something-fun-tying-the-knot"
|
||
id="toc-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"
|
||
id="toc-something-fun-debug.trace"><span
|
||
class="toc-section-number">10.9</span> Something Fun:
|
||
Debug.Trace</a></li>
|
||
<li><a href="#quiz-1" id="toc-quiz-1"><span
|
||
class="toc-section-number">10.10</span> Quiz</a></li>
|
||
<li><a href="#exercises-1" id="toc-exercises-1"><span
|
||
class="toc-section-number">10.11</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-11-realworld---arealworld"
|
||
id="toc-lecture-11-realworld---arealworld"><span
|
||
class="toc-section-number">11</span> Lecture 11:
|
||
<code>RealWorld -> (a,RealWorld)</code></a>
|
||
<ul>
|
||
<li><a href="#contents" id="toc-contents"><span
|
||
class="toc-section-number">11.1</span> Contents</a></li>
|
||
<li><a href="#youve-been-fooled" id="toc-youve-been-fooled"><span
|
||
class="toc-section-number">11.2</span> You’ve Been Fooled!</a></li>
|
||
<li><a href="#the-subtle-return" id="toc-the-subtle-return"><span
|
||
class="toc-section-number">11.3</span> The Subtle
|
||
<code>return</code></a></li>
|
||
<li><a href="#do-and-types" id="toc-do-and-types"><span
|
||
class="toc-section-number">11.4</span> <code>do</code> and
|
||
Types</a></li>
|
||
<li><a href="#control-structures" id="toc-control-structures"><span
|
||
class="toc-section-number">11.5</span> Control Structures</a></li>
|
||
<li><a href="#a-word-about-do-and-indentation"
|
||
id="toc-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" id="toc-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"
|
||
id="toc-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" id="toc-one-more-thing-ioref"><span
|
||
class="toc-section-number">11.9</span> One More Thing: IORef</a></li>
|
||
<li><a href="#summary-of-io" id="toc-summary-of-io"><span
|
||
class="toc-section-number">11.10</span> Summary of IO</a></li>
|
||
<li><a href="#quiz-2" id="toc-quiz-2"><span
|
||
class="toc-section-number">11.11</span> Quiz</a></li>
|
||
<li><a href="#exercises-2" id="toc-exercises-2"><span
|
||
class="toc-section-number">11.12</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-12-fmap-fmap-fmap"
|
||
id="toc-lecture-12-fmap-fmap-fmap"><span
|
||
class="toc-section-number">12</span> Lecture 12: fmap fmap fmap</a>
|
||
<ul>
|
||
<li><a href="#contents-1" id="toc-contents-1"><span
|
||
class="toc-section-number">12.1</span> Contents</a></li>
|
||
<li><a href="#functors" id="toc-functors"><span
|
||
class="toc-section-number">12.2</span> Functors</a></li>
|
||
<li><a href="#lawful-instances" id="toc-lawful-instances"><span
|
||
class="toc-section-number">12.3</span> Lawful Instances</a></li>
|
||
<li><a href="#sidenote-kinds" id="toc-sidenote-kinds"><span
|
||
class="toc-section-number">12.4</span> Sidenote: Kinds</a></li>
|
||
<li><a href="#foldable-again" id="toc-foldable-again"><span
|
||
class="toc-section-number">12.5</span> <code>Foldable</code>,
|
||
Again</a></li>
|
||
<li><a href="#recap" id="toc-recap"><span
|
||
class="toc-section-number">12.6</span> Recap</a></li>
|
||
<li><a href="#quiz-3" id="toc-quiz-3"><span
|
||
class="toc-section-number">12.7</span> Quiz</a></li>
|
||
<li><a href="#exercises-3" id="toc-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"
|
||
id="toc-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" id="toc-example-1-maybes"><span
|
||
class="toc-section-number">13.1</span> Example 1: Maybes</a></li>
|
||
<li><a href="#example-2-logging" id="toc-example-2-logging"><span
|
||
class="toc-section-number">13.2</span> Example 2: Logging</a></li>
|
||
<li><a href="#example-3-keeping-state"
|
||
id="toc-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"
|
||
id="toc-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" id="toc-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" id="toc-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" id="toc-logger-is-a-monad"><span
|
||
class="toc-section-number">13.7</span> Logger is a Monad!</a></li>
|
||
<li><a href="#the-state-monad" id="toc-the-state-monad"><span
|
||
class="toc-section-number">13.8</span> The State Monad</a></li>
|
||
<li><a href="#the-return-of-mapm" id="toc-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" id="toc-monads-are-functors"><span
|
||
class="toc-section-number">13.10</span> Monads are Functors</a></li>
|
||
<li><a href="#one-more-monad" id="toc-one-more-monad"><span
|
||
class="toc-section-number">13.11</span> One More Monad</a></li>
|
||
<li><a href="#oh-right-io" id="toc-oh-right-io"><span
|
||
class="toc-section-number">13.12</span> Oh Right, IO</a></li>
|
||
<li><a href="#monads-in-other-languages"
|
||
id="toc-monads-in-other-languages"><span
|
||
class="toc-section-number">13.13</span> Monads in Other
|
||
Languages</a></li>
|
||
<li><a href="#monads-wrap-up" id="toc-monads-wrap-up"><span
|
||
class="toc-section-number">13.14</span> Monads: Wrap-up</a></li>
|
||
<li><a href="#sidenote-standard-haskell"
|
||
id="toc-sidenote-standard-haskell"><span
|
||
class="toc-section-number">13.15</span> Sidenote: Standard
|
||
Haskell</a></li>
|
||
<li><a href="#quiz-4" id="toc-quiz-4"><span
|
||
class="toc-section-number">13.16</span> Quiz</a></li>
|
||
<li><a href="#exercises-4" id="toc-exercises-4"><span
|
||
class="toc-section-number">13.17</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-14-lets-use-some-libraries"
|
||
id="toc-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" id="toc-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" id="toc-monads-recap"><span
|
||
class="toc-section-number">14.2</span> Monads: Recap</a></li>
|
||
<li><a href="#writing-a-http-server-wai-and-warp"
|
||
id="toc-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"
|
||
id="toc-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" id="toc-exercises-5"><span
|
||
class="toc-section-number">14.5</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-15-youre-valid-even-without-monads"
|
||
id="toc-lecture-15-youre-valid-even-without-monads"><span
|
||
class="toc-section-number">15</span> Lecture 15: You’re Valid Even
|
||
Without Monads</a>
|
||
<ul>
|
||
<li><a href="#introduction-to-applicatives"
|
||
id="toc-introduction-to-applicatives"><span
|
||
class="toc-section-number">15.1</span> Introduction to
|
||
Applicatives</a></li>
|
||
<li><a href="#the-list-applicative" id="toc-the-list-applicative"><span
|
||
class="toc-section-number">15.2</span> The List Applicative</a></li>
|
||
<li><a href="#new-operators" id="toc-new-operators"><span
|
||
class="toc-section-number">15.3</span> New Operators</a></li>
|
||
<li><a href="#the-validation-applicative"
|
||
id="toc-the-validation-applicative"><span
|
||
class="toc-section-number">15.4</span> The Validation
|
||
Applicative</a></li>
|
||
<li><a href="#validating-lists-traverse"
|
||
id="toc-validating-lists-traverse"><span
|
||
class="toc-section-number">15.5</span> Validating Lists:
|
||
<code>traverse</code></a></li>
|
||
<li><a href="#sidenote-traversable" id="toc-sidenote-traversable"><span
|
||
class="toc-section-number">15.6</span> Sidenote:
|
||
<code>Traversable</code></a></li>
|
||
<li><a href="#dealing-with-failure-alternative"
|
||
id="toc-dealing-with-failure-alternative"><span
|
||
class="toc-section-number">15.7</span> Dealing with Failure:
|
||
<code>Alternative</code></a></li>
|
||
<li><a href="#sidenote-applicatives-in-context"
|
||
id="toc-sidenote-applicatives-in-context"><span
|
||
class="toc-section-number">15.8</span> Sidenote: Applicatives in
|
||
Context</a></li>
|
||
<li><a href="#quiz-5" id="toc-quiz-5"><span
|
||
class="toc-section-number">15.9</span> Quiz</a></li>
|
||
<li><a href="#exercises-6" id="toc-exercises-6"><span
|
||
class="toc-section-number">15.10</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-16-odds-and-ends"
|
||
id="toc-lecture-16-odds-and-ends"><span
|
||
class="toc-section-number">16</span> Lecture 16: Odds and Ends</a>
|
||
<ul>
|
||
<li><a href="#testing-with-quickcheck"
|
||
id="toc-testing-with-quickcheck"><span
|
||
class="toc-section-number">16.1</span> Testing with QuickCheck</a></li>
|
||
<li><a href="#phantom-types" id="toc-phantom-types"><span
|
||
class="toc-section-number">16.2</span> Phantom Types</a></li>
|
||
<li><a href="#simultaneity" id="toc-simultaneity"><span
|
||
class="toc-section-number">16.3</span> Simultaneity</a></li>
|
||
<li><a href="#exercises-7" id="toc-exercises-7"><span
|
||
class="toc-section-number">16.4</span> Exercises</a></li>
|
||
<li><a href="#where-to-go-from-here"
|
||
id="toc-where-to-go-from-here"><span
|
||
class="toc-section-number">16.5</span> Where to Go From Here?</a></li>
|
||
<li><a href="#acknowledgements" id="toc-acknowledgements"><span
|
||
class="toc-section-number">16.6</span> Acknowledgements</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>
|
||
<h1 data-number="9" 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 data-number="9.1" 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"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Enumeration types</span></span>
|
||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Bool</span> <span class="ot">=</span> <span class="dt">True</span> <span class="op">|</span> <span class="dt">False</span></span>
|
||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Color</span> <span class="ot">=</span> <span class="dt">Red</span> <span class="op">|</span> <span class="dt">Green</span> <span class="op">|</span> <span class="dt">Blue</span></span>
|
||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Record types that contain fields</span></span>
|
||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Vector2d</span> <span class="ot">=</span> <span class="dt">MakeVector</span> <span class="dt">Double</span> <span class="dt">Double</span></span>
|
||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Person</span> <span class="ot">=</span> <span class="dt">Person</span> <span class="dt">Int</span> <span class="dt">String</span></span>
|
||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Parameterized types. Note the type parameter `a`</span></span>
|
||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">PairOf</span> a <span class="ot">=</span> <span class="dt">TwoValues</span> a a</span>
|
||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- Recursive types</span></span>
|
||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">IntList</span> <span class="ot">=</span> <span class="dt">Empty</span> <span class="op">|</span> <span class="dt">Node</span> <span class="dt">Int</span> <span class="dt">IntList</span></span>
|
||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Complex types which combine many of these features</span></span>
|
||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Maybe</span> a <span class="ot">=</span> <span class="dt">Nothing</span> <span class="op">|</span> <span class="dt">Just</span> a</span>
|
||
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Either</span> a b <span class="ot">=</span> <span class="dt">Left</span> a <span class="op">|</span> <span class="dt">Right</span> b</span>
|
||
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Nil</span> <span class="op">|</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></span>
|
||
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Leaf</span> a <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</span>
|
||
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">MultiTree</span> a <span class="ot">=</span> <span class="dt">MultiTree</span> a [<span class="dt">MultiTree</span> a] <span class="co">-- Note the list</span></span></code></pre></div>
|
||
<p>Values of these types include:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 82%" />
|
||
<col style="width: 17%" />
|
||
</colgroup>
|
||
<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>Cons 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"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>[a] <span class="ot">-></span> [a] <span class="co">-- function from list of any type, to list of the same type</span></span>
|
||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>[a] <span class="ot">-></span> a <span class="co">-- function from list of any type, to the element type</span></span>
|
||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a>(a,b) <span class="ot">-></span> [a] <span class="co">-- function from tuple to list</span></span></code></pre></div>
|
||
<h3 data-number="9.1.1" 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, that notation is just a shorthand
|
||
as lists are actually built up of the list constructors <code>[]</code>
|
||
and <code>(:)</code>. These constructors are also used when pattern
|
||
matching lists. Here are some examples of lists:</p>
|
||
<table>
|
||
<colgroup>
|
||
<col style="width: 34%" />
|
||
<col style="width: 56%" />
|
||
<col style="width: 9%" />
|
||
</colgroup>
|
||
<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>
|
||
<colgroup>
|
||
<col style="width: 23%" />
|
||
<col style="width: 76%" />
|
||
</colgroup>
|
||
<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>[x .. y]</code></td>
|
||
<td style="text-align: left;">everything from <code>x</code> to
|
||
<code>y</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>[y, y-1 .. x]</code></td>
|
||
<td style="text-align: left;">everything from <code>y</code> to
|
||
<code>x</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 powerful way to 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>
|
||
<p>Just one more note on the syntax. Recall that <code>(:)</code>
|
||
associates to the right, e.g. <code>True:False:[]</code> is the same as
|
||
<code>True:(False:[])</code>. (In fact, <code>(True:False):[]</code> is
|
||
not even a list, because <code>True:False</code> attempts to add
|
||
<code>True</code> in front of <code>False</code> which is not a
|
||
list.)</p>
|
||
<h2 data-number="9.2" 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"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ot">functionName ::</span> argumentType <span class="ot">-></span> returnType</span>
|
||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>functionName argument <span class="ot">=</span> returnValue</span></code></pre></div>
|
||
<p>For example:</p>
|
||
<div class="sourceCode" id="cb4"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ot">repeatString ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>repeatString s <span class="ot">=</span> s <span class="op">++</span> s</span></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"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>surroundString around s <span class="ot">=</span> around <span class="op">++</span> s <span class="op">++</span> around</span></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"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span><span class="ot"> ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span> x <span class="ot">=</span> x</span>
|
||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="fu">const</span><span class="ot"> ::</span> a <span class="ot">-></span> b <span class="ot">-></span> a</span>
|
||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="fu">const</span> x y <span class="ot">=</span> x</span>
|
||
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="fu">flip</span><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</span>
|
||
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="fu">flip</span> f x y <span class="ot">=</span> f y x</span></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>Maybe</code>, and also lists with the
|
||
constructors <code>[]</code> and <code>(:)</code>.</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ot">swap ::</span> (a,b) <span class="ot">-></span> (b,a)</span>
|
||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>swap (x,y) <span class="ot">=</span> (y,x)</span>
|
||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="fu">maybe</span><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</span>
|
||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="fu">maybe</span> def _ <span class="dt">Nothing</span> <span class="ot">=</span> def</span>
|
||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="fu">maybe</span> _ f (<span class="dt">Just</span> x) <span class="ot">=</span> f x</span>
|
||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>safeHead [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>safeHead (x<span class="op">:</span>_) <span class="ot">=</span> <span class="dt">Just</span> x</span></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"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ot">myAbs ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>myAbs x</span>
|
||
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op"><</span> <span class="dv">0</span> <span class="ot">=</span> <span class="op">-</span>x</span>
|
||
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x</span>
|
||
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>safeDiv x y</span>
|
||
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> y <span class="op">==</span> <span class="dv">0</span> <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Just</span> (x <span class="op">/</span> y)</span>
|
||
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>buy <span class="st">"Banana"</span> money</span>
|
||
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> money <span class="op"><</span> <span class="fl">3.2</span> <span class="ot">=</span> <span class="st">"You don't have enough money for a banana"</span></span>
|
||
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="st">"You bought a banana"</span></span>
|
||
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>buy <span class="fu">product</span> _ <span class="ot">=</span> <span class="st">"No such product: "</span> <span class="op">++</span> <span class="fu">product</span></span></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"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>divDefault x y def <span class="ot">=</span> <span class="kw">case</span> safeDiv x y <span class="kw">of</span></span>
|
||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> def</span>
|
||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> w <span class="ot">-></span> w</span></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"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ot">circleArea ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>circleArea r <span class="ot">=</span> <span class="kw">let</span> <span class="fu">pi</span> <span class="ot">=</span> <span class="fl">3.1415926</span></span>
|
||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> square x <span class="ot">=</span> x <span class="op">*</span> x</span>
|
||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">pi</span> <span class="op">*</span> square r</span>
|
||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="ot">circleArea' ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>circleArea' r <span class="ot">=</span> <span class="fu">pi</span> <span class="op">*</span> square r</span>
|
||
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> <span class="fu">pi</span> <span class="ot">=</span> <span class="fl">3.1415926</span></span>
|
||
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a> square x <span class="ot">=</span> x <span class="op">*</span> x</span></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"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="ot">incrementAll ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>incrementAll xs <span class="ot">=</span> <span class="fu">map</span> (\x <span class="ot">-></span> x <span class="op">+</span> <span class="dv">1</span>) xs</span></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"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ot">incrementAll' ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>incrementAll' xs <span class="ot">=</span> <span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) xs</span></code></pre></div>
|
||
<h2 data-number="9.3" 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"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- a predicate that checks if a string is a palindrome</span></span>
|
||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ot">palindrome ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>palindrome str <span class="ot">=</span> str <span class="op">==</span> <span class="fu">reverse</span> str</span>
|
||
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- palindromes n takes all numbers from 1 to n, converts them to</span></span>
|
||
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- strings using show, and keeps only palindromes</span></span>
|
||
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="ot">palindromes ::</span> <span class="dt">Int</span> <span class="ot">-></span> [<span class="dt">String</span>]</span>
|
||
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>palindromes n <span class="ot">=</span> <span class="fu">filter</span> palindrome (<span class="fu">map</span> <span class="fu">show</span> [<span class="dv">1</span><span class="op">..</span>n])</span></code></pre></div>
|
||
<div class="sourceCode" id="cb14"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>palindromes <span class="dv">150</span></span>
|
||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>,</span>
|
||
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <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>,</span>
|
||
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <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>]</span></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"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="fu">take</span> <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>]]</span>
|
||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]]</span></code></pre></div>
|
||
<p>Also, <em>function composition</em>:</p>
|
||
<div class="sourceCode" id="cb16"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>(<span class="fu">map</span> <span class="fu">reverse</span> <span class="op">.</span> <span class="fu">filter</span> (<span class="op">/=</span><span class="st">"Smith"</span>)) [<span class="st">"Jones"</span>,<span class="st">"Smith"</span>,<span class="st">"White"</span>]</span>
|
||
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"senoJ"</span>,<span class="st">"etihW"</span>]</span>
|
||
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="fu">negate</span> <span class="op">.</span> <span class="fu">sum</span>) [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[<span class="dv">5</span>]]</span>
|
||
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="op">-</span><span class="dv">6</span>,<span class="op">-</span><span class="dv">5</span>]</span></code></pre></div>
|
||
<p>And finally, <em>folds</em>:</p>
|
||
<div class="sourceCode" id="cb17"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">*</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>] <span class="op">==></span> <span class="dv">24</span></span>
|
||
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> <span class="fu">max</span> <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">7</span>] <span class="op">==></span> <span class="dv">7</span></span>
|
||
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">++</span>) <span class="st">""</span> [<span class="st">"abc"</span>,<span class="st">"de"</span>,<span class="st">"f"</span>] <span class="op">==></span> <span class="st">"abcdef"</span></span></code></pre></div>
|
||
<h2 data-number="9.4" 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"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="ot">repeatString ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>repeatString <span class="dv">0</span> s <span class="ot">=</span> <span class="st">""</span></span>
|
||
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>repeatString n s <span class="ot">=</span> s <span class="op">++</span> repeatString (n<span class="op">-</span><span class="dv">1</span>) s</span>
|
||
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>times <span class="dv">0</span> n <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>times <span class="dv">1</span> n <span class="ot">=</span> n</span>
|
||
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>times m n <span class="ot">=</span> n <span class="op">+</span> times (m <span class="op">-</span> <span class="dv">1</span>) n</span>
|
||
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a><span class="ot">safeLast ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb18-11"><a href="#cb18-11" aria-hidden="true" tabindex="-1"></a>safeLast [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb18-12"><a href="#cb18-12" aria-hidden="true" tabindex="-1"></a>safeLast [x] <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb18-13"><a href="#cb18-13" aria-hidden="true" tabindex="-1"></a>safeLast (x<span class="op">:</span>xs) <span class="ot">=</span> safeLast xs</span></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"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span><span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f (x<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> <span class="fu">map</span> f xs</span>
|
||
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span><span class="ot"> ::</span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> <span class="fu">pred</span> (x<span class="op">:</span>xs)</span>
|
||
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">pred</span> x <span class="ot">=</span> x <span class="op">:</span> <span class="fu">filter</span> <span class="fu">pred</span> xs</span>
|
||
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">filter</span> <span class="fu">pred</span> xs</span></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"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="ot">sumNumbers ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>sumNumbers xs <span class="ot">=</span> go <span class="dv">0</span> xs</span>
|
||
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go <span class="fu">sum</span> [] <span class="ot">=</span> <span class="fu">sum</span></span>
|
||
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> go <span class="fu">sum</span> (x<span class="op">:</span>xs) <span class="ot">=</span> go (<span class="fu">sum</span><span class="op">+</span>x) xs</span></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"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- split a string into pieces at the given character</span></span>
|
||
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a><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>]</span>
|
||
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>mySplit c xs <span class="ot">=</span> helper [] xs</span>
|
||
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> helper piece [] <span class="ot">=</span> [piece]</span>
|
||
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a> helper piece (y<span class="op">:</span>ys)</span>
|
||
<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> c <span class="op">==</span> y <span class="ot">=</span> piece <span class="op">:</span> helper [] ys</span>
|
||
<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> helper (piece<span class="op">++</span>[y]) ys</span></code></pre></div>
|
||
<div class="sourceCode" id="cb22"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>mySplit <span class="ch">'-'</span> <span class="st">"a-bcd-ef"</span> <span class="op">==></span> [<span class="st">"a"</span>,<span class="st">"bcd"</span>,<span class="st">"ef"</span>]</span></code></pre></div>
|
||
<h2 data-number="9.5" 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"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span><span class="ot"> ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span> x <span class="ot">=</span> x</span>
|
||
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span><span class="ot"> ::</span> [a] <span class="ot">-></span> a</span>
|
||
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (x<span class="op">:</span>_) <span class="ot">=</span> x</span>
|
||
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="fu">fst</span><span class="ot"> ::</span> (a,b) <span class="ot">-></span> a</span>
|
||
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a><span class="fu">fst</span> (x,y) <span class="ot">=</span> x</span></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"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="fu">negate</span><span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="fu">sort</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> [a] <span class="ot">-></span> [a]</span></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"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">negate</span> <span class="dv">1</span></span>
|
||
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">negate</span> <span class="fl">1.0</span></span>
|
||
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a><span class="op">-</span><span class="fl">1.0</span></span>
|
||
<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">negate</span> <span class="dt">True</span></span>
|
||
<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">3</span><span class="op">:</span><span class="dv">1</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a> • <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’</span></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"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>sumTwoSmallest xs <span class="ot">=</span> <span class="kw">let</span> (a<span class="op">:</span>b<span class="op">:</span>_) <span class="ot">=</span> <span class="fu">sort</span> xs</span>
|
||
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> a<span class="op">+</span>b</span></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"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Sized</span> a <span class="kw">where</span></span>
|
||
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> empty ::</span> a <span class="co">-- a thing with size 0</span></span>
|
||
<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> size ::</span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Eq</span> a <span class="kw">where</span></span>
|
||
<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> (==) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<p>Consider the following data structures:</p>
|
||
<div class="sourceCode" id="cb28"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Numbers</span> <span class="ot">=</span> <span class="dt">None</span> <span class="op">|</span> <span class="dt">One</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Two</span> <span class="dt">Int</span> <span class="dt">Int</span></span>
|
||
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">IntList</span> <span class="ot">=</span> <span class="dt">Nil</span> <span class="op">|</span> <span class="dt">ListNode</span> <span class="dt">Int</span> <span class="dt">IntList</span></span>
|
||
<span id="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Leaf</span> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</span></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"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Sized</span> <span class="dt">Numbers</span> <span class="kw">where</span></span>
|
||
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">None</span></span>
|
||
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a> size <span class="dt">None</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a> size (<span class="dt">One</span> _) <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a> size (<span class="dt">Two</span> _ _) <span class="ot">=</span> <span class="dv">2</span></span>
|
||
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb29-7"><a href="#cb29-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Sized</span> <span class="dt">IntList</span> <span class="kw">where</span></span>
|
||
<span id="cb29-8"><a href="#cb29-8" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">Nil</span></span>
|
||
<span id="cb29-9"><a href="#cb29-9" aria-hidden="true" tabindex="-1"></a> size <span class="dt">Nil</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb29-10"><a href="#cb29-10" aria-hidden="true" tabindex="-1"></a> size (<span class="dt">ListNode</span> _ list) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> size list</span>
|
||
<span id="cb29-11"><a href="#cb29-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb29-12"><a href="#cb29-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Sized</span> (<span class="dt">Tree</span> a) <span class="kw">where</span></span>
|
||
<span id="cb29-13"><a href="#cb29-13" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">Leaf</span></span>
|
||
<span id="cb29-14"><a href="#cb29-14" aria-hidden="true" tabindex="-1"></a> size <span class="dt">Leaf</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb29-15"><a href="#cb29-15" aria-hidden="true" tabindex="-1"></a> size (<span class="dt">Node</span> _ left right) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> size left <span class="op">+</span> size right</span></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"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">Numbers</span> <span class="kw">where</span></span>
|
||
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">None</span> <span class="op">==</span> <span class="dt">None</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a> (<span class="dt">One</span> x) <span class="op">==</span> (<span class="dt">One</span> y) <span class="ot">=</span> x<span class="op">==</span>y</span>
|
||
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Two</span> x y) <span class="op">==</span> (<span class="dt">Two</span> z w) <span class="ot">=</span> x<span class="op">==</span>z <span class="op">&&</span> y<span class="op">==</span>w</span>
|
||
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a> _ <span class="op">==</span> _ <span class="ot">=</span> <span class="dt">False</span> <span class="co">-- to handle cases like None == One 1</span></span>
|
||
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">IntList</span> <span class="kw">where</span></span>
|
||
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nil</span> <span class="op">==</span> <span class="dt">Nil</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a> (<span class="dt">ListNode</span> x xs) <span class="op">==</span> (<span class="dt">ListNode</span> y ys) <span class="ot">=</span> x <span class="op">==</span> y <span class="op">&&</span> xs <span class="op">==</span> ys</span>
|
||
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a> _ <span class="op">==</span> _ <span class="ot">=</span> <span class="dt">False</span></span></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"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">Leaf</span> <span class="op">==</span> <span class="dt">Leaf</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb31-3"><a href="#cb31-3" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Node</span> x l r) <span class="op">==</span> (<span class="dt">Node</span> x' l' r') <span class="ot">=</span> x <span class="op">==</span> x' <span class="op">&&</span> l <span class="op">==</span> l' <span class="op">&&</span> r <span class="op">==</span> r'</span>
|
||
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> _ <span class="op">==</span> _ <span class="ot">=</span> <span class="dt">False</span></span></code></pre></div>
|
||
<h3 data-number="9.5.1" 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"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Numbers</span> <span class="ot">=</span> <span class="dt">None</span> <span class="op">|</span> <span class="dt">One</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Two</span> <span class="dt">Int</span> <span class="dt">Int</span></span>
|
||
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a> <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>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb33"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="dt">None</span> <span class="op">==</span> <span class="dt">One</span> <span class="dv">1</span> <span class="op">==></span> <span class="dt">False</span></span>
|
||
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="op">==</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">True</span></span>
|
||
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="dt">None</span> <span class="op"><</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">True</span></span>
|
||
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Two</span> <span class="dv">1</span> <span class="dv">3</span> <span class="op"><</span> <span class="dt">Two</span> <span class="dv">1</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">False</span></span>
|
||
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a><span class="fu">show</span> (<span class="dt">Two</span> <span class="dv">1</span> <span class="dv">3</span>) <span class="op">==></span> <span class="st">"Two 1 3"</span></span></code></pre></div>
|
||
<h2 data-number="9.6" 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"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">T</span> <span class="ot">=</span> <span class="dt">X</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Y</span> <span class="dt">String</span> <span class="dt">String</span> <span class="op">|</span> <span class="dt">Z</span> <span class="dt">T</span></span></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"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a>f (_<span class="op">:</span><span class="dt">Just</span> x<span class="op">:</span>_) <span class="ot">=</span> x</span>
|
||
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>f _ <span class="ot">=</span> <span class="dt">False</span></span></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"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a>f x y <span class="ot">=</span> x<span class="op">-</span>y <span class="op">==</span> <span class="dv">0</span></span></code></pre></div>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>(Num a, Eq a) => a -> a -> Bool</code>
|
||
</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>
|
||
<p>Which of the following types can <code>x</code> have in order for
|
||
<code>x (&&) y</code> to not be a type error?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>Bool -> Bool -> Bool</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(Bool -> Bool -> Bool) -> Bool -> Bool</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="9.7" 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 data-number="9.8" 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>
|
||
</ul>
|
||
<h1 data-number="10" 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 data-number="10.1" 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"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> f x <span class="co">-- infinite recursion</span></span>
|
||
<span id="cb37-2"><a href="#cb37-2" aria-hidden="true" tabindex="-1"></a>g x y <span class="ot">=</span> x</span></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"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a>g <span class="dv">2</span> (f <span class="dv">1</span>) <span class="op">==></span> <span class="dv">2</span></span></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 data-number="10.2" 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"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> <span class="fu">reverse</span> <span class="op">.</span> <span class="fu">map</span> (<span class="op">-</span><span class="dv">1</span>)</span></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"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a>((<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> (<span class="op">-</span><span class="dv">1</span>)) x <span class="op">===</span> ((<span class="op">+</span><span class="dv">1</span>) ((<span class="op">-</span><span class="dv">1</span>) x))</span>
|
||
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a> <span class="op">===</span> ((<span class="op">+</span><span class="dv">1</span>) (x <span class="op">-</span> <span class="dv">1</span>))</span>
|
||
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a> <span class="op">===</span> (x <span class="op">-</span> <span class="dv">1</span>) <span class="op">+</span> <span class="dv">1</span></span>
|
||
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a> <span class="op">===</span> x</span>
|
||
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a> <span class="op">===</span> <span class="fu">id</span> x</span></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>every</em>
|
||
<code>x</code>. Thus,</p>
|
||
<div class="sourceCode" id="cb42"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a>(<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> (<span class="op">-</span><span class="dv">1</span>) <span class="op">===</span> <span class="fu">id</span></span></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"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> <span class="fu">reverse</span> <span class="op">.</span> <span class="fu">map</span> (<span class="op">-</span><span class="dv">1</span>)</span>
|
||
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> (<span class="fu">reverse</span> <span class="op">.</span> <span class="fu">map</span> (<span class="op">-</span><span class="dv">1</span>)) <span class="co">-- By associativity of (.)</span></span>
|
||
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> (<span class="fu">map</span> (<span class="op">-</span><span class="dv">1</span>) <span class="op">.</span> <span class="fu">reverse</span>) <span class="co">-- By fact 3</span></span>
|
||
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> (<span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> <span class="fu">map</span> (<span class="op">-</span><span class="dv">1</span>)) <span class="op">.</span> <span class="fu">reverse</span> <span class="co">-- By associativity of (.)</span></span>
|
||
<span id="cb43-5"><a href="#cb43-5" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">map</span> ((<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> (<span class="op">-</span><span class="dv">1</span>)) <span class="op">.</span> <span class="fu">reverse</span> <span class="co">-- By fact 2</span></span>
|
||
<span id="cb43-6"><a href="#cb43-6" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">map</span> <span class="fu">id</span> <span class="op">.</span> <span class="fu">reverse</span> <span class="co">-- By fact 4</span></span>
|
||
<span id="cb43-7"><a href="#cb43-7" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">id</span> <span class="op">.</span> <span class="fu">reverse</span> <span class="co">-- By fact 1</span></span>
|
||
<span id="cb43-8"><a href="#cb43-8" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">reverse</span> <span class="co">-- By the definition of id</span></span></code></pre></div>
|
||
<p>This course won’t go into details about proving things about
|
||
programs, but it’s good to know that pure functional programming is very
|
||
compatible with analysis like this.</p>
|
||
<h2 data-number="10.3" 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"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">repeat</span> <span class="dv">1</span></span>
|
||
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a>[<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></span>
|
||
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a><span class="op">^</span><span class="dt">C</span></span></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"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">10</span> <span class="op">$</span> <span class="fu">repeat</span> <span class="dv">1</span></span>
|
||
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a>[<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>
|
||
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">20</span> <span class="op">$</span> <span class="fu">repeat</span> <span class="dv">1</span></span>
|
||
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a>[<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>
|
||
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">repeat</span> <span class="dv">1</span> <span class="op">!!</span> <span class="dv">13337</span></span>
|
||
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span></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"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">20</span> [<span class="dv">0</span><span class="op">..</span>]</span>
|
||
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>[<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>]</span>
|
||
<span id="cb46-3"><a href="#cb46-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">10</span> <span class="op">.</span> <span class="fu">map</span> (<span class="dv">2</span><span class="op">^</span>) <span class="op">$</span> [<span class="dv">0</span><span class="op">..</span>]</span>
|
||
<span id="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a>[<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>]</span></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"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">21</span> <span class="op">$</span> <span class="fu">cycle</span> <span class="st">"asdf"</span></span>
|
||
<span id="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a><span class="st">"asdfasdfasdfasdfasdfa"</span></span>
|
||
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">4</span> <span class="op">.</span> <span class="fu">map</span> (<span class="fu">take</span> <span class="dv">4</span>) <span class="op">.</span> tails <span class="op">$</span> <span class="fu">cycle</span> <span class="st">"asdf"</span></span>
|
||
<span id="cb47-4"><a href="#cb47-4" aria-hidden="true" tabindex="-1"></a>[<span class="st">"asdf"</span>,<span class="st">"sdfa"</span>,<span class="st">"dfas"</span>,<span class="st">"fasd"</span>]</span></code></pre></div>
|
||
<h3 data-number="10.3.1" 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"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="ot">viitenumeroCheck ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>viitenumeroCheck allDigits <span class="ot">=</span> <span class="fu">mod</span> (checksum<span class="op">+</span>checkDigit) <span class="dv">10</span> <span class="op">==</span> <span class="dv">0</span></span>
|
||
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> (checkDigit<span class="op">:</span>digits) <span class="ot">=</span> <span class="fu">reverse</span> allDigits</span>
|
||
<span id="cb49-4"><a href="#cb49-4" aria-hidden="true" tabindex="-1"></a> multipliers <span class="ot">=</span> <span class="fu">cycle</span> [<span class="dv">7</span>,<span class="dv">3</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb49-5"><a href="#cb49-5" aria-hidden="true" tabindex="-1"></a> checksum <span class="ot">=</span> <span class="fu">sum</span> <span class="op">$</span> <span class="fu">zipWith</span> (<span class="op">*</span>) multipliers digits</span></code></pre></div>
|
||
<div class="sourceCode" id="cb50"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a>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="op">==></span> <span class="dt">True</span></span>
|
||
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>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="op">==></span> <span class="dt">False</span></span></code></pre></div>
|
||
<h3 data-number="10.3.2" 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"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">head</span> <span class="op">.</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) <span class="op">$</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">0</span><span class="op">..</span>]</span>
|
||
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a><span class="dv">243</span></span></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"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) (<span class="dv">0</span><span class="op">:</span>[<span class="dv">1</span><span class="op">..</span>]))) <span class="co">-- evaluate first element of the lazy list</span></span>
|
||
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">1</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>])) <span class="co">-- map processes the element</span></span>
|
||
<span id="cb52-4"><a href="#cb52-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>])) <span class="co">-- filter drops the element</span></span>
|
||
<span id="cb52-5"><a href="#cb52-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) (<span class="dv">1</span><span class="op">:</span>[<span class="dv">2</span><span class="op">..</span>]))) <span class="co">-- evaluate second element of the lazy list</span></span>
|
||
<span id="cb52-6"><a href="#cb52-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">3</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">2</span><span class="op">..</span>])) <span class="co">-- map processes the element</span></span>
|
||
<span id="cb52-7"><a href="#cb52-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">2</span><span class="op">..</span>])) <span class="co">-- filter drops the element</span></span>
|
||
<span id="cb52-8"><a href="#cb52-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- let's take bigger steps now</span></span>
|
||
<span id="cb52-9"><a href="#cb52-9" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">9</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">3</span><span class="op">..</span>])) <span class="co">-- map processes, filter will drop</span></span>
|
||
<span id="cb52-10"><a href="#cb52-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">27</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">4</span><span class="op">..</span>])) <span class="co">-- map processes, filter will drop</span></span>
|
||
<span id="cb52-11"><a href="#cb52-11" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">81</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">5</span><span class="op">..</span>])) <span class="co">-- map processes, filter will drop</span></span>
|
||
<span id="cb52-12"><a href="#cb52-12" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">243</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">6</span><span class="op">..</span>])) <span class="co">-- map processes</span></span>
|
||
<span id="cb52-13"><a href="#cb52-13" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="dv">243</span> <span class="op">:</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">6</span><span class="op">..</span>])) <span class="co">-- filter lets the value through</span></span>
|
||
<span id="cb52-14"><a href="#cb52-14" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">243</span> <span class="co">-- head returns the result</span></span></code></pre></div>
|
||
<h2 data-number="10.4" 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"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>g x y <span class="ot">=</span> y<span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb53-4"><a href="#cb53-4" aria-hidden="true" tabindex="-1"></a>f a b c <span class="ot">=</span> g (a<span class="op">*</span><span class="dv">1000</span>) c</span></code></pre></div>
|
||
<p>Inside-out (normal) evaluation:</p>
|
||
<div class="sourceCode" id="cb54"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a>f <span class="dv">1</span> (<span class="dv">1234</span><span class="op">*</span><span class="dv">1234</span>) <span class="dv">2</span></span>
|
||
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate arguments to f</span></span>
|
||
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> f <span class="dv">1</span> <span class="dv">1522756</span> <span class="dv">2</span></span>
|
||
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate f</span></span>
|
||
<span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> g (<span class="dv">1</span><span class="op">*</span><span class="dv">1000</span>) <span class="dv">2</span></span>
|
||
<span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate arguments to g</span></span>
|
||
<span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> g <span class="dv">1000</span> <span class="dv">2</span></span>
|
||
<span id="cb54-8"><a href="#cb54-8" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate g</span></span>
|
||
<span id="cb54-9"><a href="#cb54-9" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span><span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb54-10"><a href="#cb54-10" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>Haskell outside-in evaluation:</p>
|
||
<div class="sourceCode" id="cb55"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a>f <span class="dv">1</span> (<span class="dv">1234</span><span class="op">*</span><span class="dv">1234</span>) <span class="dv">2</span></span>
|
||
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate f without evaluating arguments</span></span>
|
||
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> g (<span class="dv">1</span><span class="op">*</span><span class="dv">1000</span>) <span class="dv">2</span></span>
|
||
<span id="cb55-4"><a href="#cb55-4" aria-hidden="true" tabindex="-1"></a> <span class="co">-- evaluate g without evaluating arguments</span></span>
|
||
<span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span><span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb55-6"><a href="#cb55-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span></span></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 data-number="10.4.1" 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"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="dt">True</span> <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="dt">False</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f [] <span class="ot">=</span> []</span>
|
||
<span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f (x<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> <span class="fu">map</span> f xs</span>
|
||
<span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb56-6"><a href="#cb56-6" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dv">1</span><span class="op">+</span><span class="fu">length</span> xs</span></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"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (<span class="fu">map</span> <span class="fu">not</span> (<span class="dt">True</span><span class="op">:</span><span class="dt">False</span><span class="op">:</span>[]))</span>
|
||
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">length</span> (<span class="fu">not</span> <span class="dt">True</span> <span class="op">:</span> <span class="fu">not</span> <span class="dt">False</span> <span class="op">:</span> []) <span class="co">-- evaluate call to map</span></span>
|
||
<span id="cb57-3"><a href="#cb57-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">length</span> (<span class="dt">False</span><span class="op">:</span><span class="dt">True</span><span class="op">:</span>[]) <span class="co">-- evaluate calls to not</span></span>
|
||
<span id="cb57-4"><a href="#cb57-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span></span></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"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (<span class="fu">map</span> <span class="fu">not</span> (<span class="dt">True</span><span class="op">:</span><span class="dt">False</span><span class="op">:</span>[]))</span>
|
||
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- We can't evaluate length since we don't know which equation of length applies,</span></span>
|
||
<span id="cb58-3"><a href="#cb58-3" aria-hidden="true" tabindex="-1"></a> <span class="co">-- so we look at length's argument. We can apply the second equation of map, so we do.</span></span>
|
||
<span id="cb58-4"><a href="#cb58-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">length</span> (<span class="fu">not</span> <span class="dt">True</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">not</span> (<span class="dt">False</span><span class="op">:</span>[]))</span>
|
||
<span id="cb58-5"><a href="#cb58-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Now the argument of length has a (:) we can pattern match on, so we apply the</span></span>
|
||
<span id="cb58-6"><a href="#cb58-6" aria-hidden="true" tabindex="-1"></a> <span class="co">-- second equation of length</span></span>
|
||
<span id="cb58-7"><a href="#cb58-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">length</span> (<span class="fu">map</span> <span class="fu">not</span> (<span class="dt">False</span><span class="op">:</span>[]))</span>
|
||
<span id="cb58-8"><a href="#cb58-8" aria-hidden="true" tabindex="-1"></a> <span class="co">-- The outermost function is now +, but it can't do anything unless both arguments</span></span>
|
||
<span id="cb58-9"><a href="#cb58-9" aria-hidden="true" tabindex="-1"></a> <span class="co">-- are numbers. So we need to evaluate length. In order to pick an equation, we need</span></span>
|
||
<span id="cb58-10"><a href="#cb58-10" aria-hidden="true" tabindex="-1"></a> <span class="co">-- to evaluate the argument of length again. We apply the second equation of map</span></span>
|
||
<span id="cb58-11"><a href="#cb58-11" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">length</span> (<span class="fu">not</span> <span class="dt">False</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">not</span> ([]))</span>
|
||
<span id="cb58-12"><a href="#cb58-12" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Now we can apply the second equation of length again.</span></span>
|
||
<span id="cb58-13"><a href="#cb58-13" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">1</span> <span class="op">+</span> <span class="fu">length</span> (<span class="fu">map</span> <span class="fu">not</span> []))</span>
|
||
<span id="cb58-14"><a href="#cb58-14" aria-hidden="true" tabindex="-1"></a> <span class="co">-- The outermost + needs a number to be evaluated. The second + also needs a number.</span></span>
|
||
<span id="cb58-15"><a href="#cb58-15" aria-hidden="true" tabindex="-1"></a> <span class="co">-- We need to evaluate length again, which means we need to pick an equation for length,</span></span>
|
||
<span id="cb58-16"><a href="#cb58-16" aria-hidden="true" tabindex="-1"></a> <span class="co">-- which means we need to evaluate its argument. This time it is the first equation for</span></span>
|
||
<span id="cb58-17"><a href="#cb58-17" aria-hidden="true" tabindex="-1"></a> <span class="co">-- map that applies.</span></span>
|
||
<span id="cb58-18"><a href="#cb58-18" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">1</span> <span class="op">+</span> <span class="fu">length</span> [])</span>
|
||
<span id="cb58-19"><a href="#cb58-19" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Now we can apply the first equation for length</span></span>
|
||
<span id="cb58-20"><a href="#cb58-20" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">1</span> <span class="op">+</span> <span class="dv">0</span>)</span>
|
||
<span id="cb58-21"><a href="#cb58-21" aria-hidden="true" tabindex="-1"></a> <span class="co">-- The outermost + still can't be evaluated, but the inner one can</span></span>
|
||
<span id="cb58-22"><a href="#cb58-22" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">1</span></span>
|
||
<span id="cb58-23"><a href="#cb58-23" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Finally we evaluate the outer +</span></span>
|
||
<span id="cb58-24"><a href="#cb58-24" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span></span></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 pick an equation for
|
||
<code>length</code> in <code>length (map not (False:[]))</code>. The
|
||
argument <code>(map not ...)</code> is not in WHNF, so it can’t be
|
||
pattern matched on. Thus we need to evaluate it. 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 data-number="10.4.2" 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"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a>square x <span class="ot">=</span> x<span class="op">*</span>x</span></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"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a>square (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>)</span>
|
||
<span id="cb60-2"><a href="#cb60-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>) <span class="op">*</span> (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>) <span class="co">-- definition of square</span></span>
|
||
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">4</span> <span class="op">*</span> (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>) <span class="co">-- (*) forces left argument</span></span>
|
||
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">4</span> <span class="op">*</span> <span class="dv">4</span> <span class="co">-- (*) forces right argument</span></span>
|
||
<span id="cb60-5"><a href="#cb60-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">16</span> <span class="co">-- definition of (*)</span></span></code></pre></div>
|
||
<!--
|
||
```haskell
|
||
square ==> * ==> * ==> * ==> 16
|
||
| / \ / \ / \
|
||
+ + + 4 + 4 4
|
||
/ \ / \ / \ / \
|
||
2 2 2 2 2 2 2 2
|
||
```
|
||
-->
|
||
<p><img src="img/square1.svg" /></p>
|
||
<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="cb61"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a>square (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>)</span>
|
||
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>) <span class="op">*</span> (<span class="dv">2</span><span class="op">+</span><span class="dv">2</span>)</span>
|
||
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">4</span> <span class="op">*</span> <span class="dv">4</span></span>
|
||
<span id="cb61-4"><a href="#cb61-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">16</span></span></code></pre></div>
|
||
<!--
|
||
```haskell
|
||
square ==> * ==> * ==> 16
|
||
| / \ / \
|
||
| \ / \ /
|
||
+ + 4
|
||
/ \ / \
|
||
2 2 2 2
|
||
```
|
||
-->
|
||
<p><img src="img/square2.svg" /></p>
|
||
<p>As another example, consider the function <code>f</code> below and
|
||
its evaluation.</p>
|
||
<div class="sourceCode" id="cb62"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a>f i <span class="ot">=</span> <span class="kw">if</span> i<span class="op">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> i</span></code></pre></div>
|
||
<div class="sourceCode" id="cb63"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a> _______shared________</span>
|
||
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">|</span></span>
|
||
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a>f (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>) <span class="op">==></span> <span class="kw">if</span> (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>)<span class="op">></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="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="kw">if</span> <span class="dv">2</span><span class="op">></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></span>
|
||
<span id="cb63-5"><a href="#cb63-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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></span>
|
||
<span id="cb63-6"><a href="#cb63-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span></span></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="cb64"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a>g i j <span class="ot">=</span> <span class="kw">if</span> i<span class="op">></span><span class="dv">10</span> <span class="kw">then</span> <span class="dv">10</span> <span class="kw">else</span> j</span></code></pre></div>
|
||
<div class="sourceCode" id="cb65"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a> ______no sharing_____</span>
|
||
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">|</span></span>
|
||
<span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a>g (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>) (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>) <span class="op">==></span> <span class="kw">if</span> (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>)<span class="op">></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="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb65-4"><a href="#cb65-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="kw">if</span> <span class="dv">2</span><span class="op">></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="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb65-5"><a href="#cb65-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb65-6"><a href="#cb65-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb65-7"><a href="#cb65-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span></span></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 data-number="10.4.3" 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="cb66"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb66-1"><a href="#cb66-1" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span><span class="ot"> ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb66-2"><a href="#cb66-2" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="dt">True</span> <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb66-3"><a href="#cb66-3" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="dt">False</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb66-4"><a href="#cb66-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb66-5"><a href="#cb66-5" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb66-6"><a href="#cb66-6" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span> <span class="op">||</span> _ <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb66-7"><a href="#cb66-7" aria-hidden="true" tabindex="-1"></a>_ <span class="op">||</span> x <span class="ot">=</span> x</span>
|
||
<span id="cb66-8"><a href="#cb66-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb66-9"><a href="#cb66-9" aria-hidden="true" tabindex="-1"></a><span class="fu">even</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb66-10"><a href="#cb66-10" aria-hidden="true" tabindex="-1"></a><span class="fu">even</span> x <span class="ot">=</span> (x <span class="op">==</span> <span class="dv">0</span>) <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> (x<span class="op">-</span><span class="dv">1</span>))</span></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="cb67"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb67-1"><a href="#cb67-1" aria-hidden="true" tabindex="-1"></a><span class="fu">even</span> <span class="dv">2</span></span>
|
||
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">2</span> <span class="op">==</span> <span class="dv">0</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">2</span><span class="op">-</span><span class="dv">1</span>)) <span class="co">-- apply definition of even</span></span>
|
||
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">False</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">2</span><span class="op">-</span><span class="dv">1</span>)) <span class="co">-- || forces its first argument</span></span>
|
||
<span id="cb67-4"><a href="#cb67-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">2</span><span class="op">-</span><span class="dv">1</span>)) <span class="co">-- second equation of ||</span></span>
|
||
<span id="cb67-5"><a href="#cb67-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> ((<span class="dv">2</span><span class="op">-</span><span class="dv">1</span>) <span class="op">==</span> <span class="dv">0</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> ((<span class="dv">2</span><span class="op">-</span><span class="dv">1</span>)<span class="op">-</span><span class="dv">1</span>))) <span class="co">-- not forces its argument: apply definition of even</span></span>
|
||
<span id="cb67-6"><a href="#cb67-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> ( <span class="dv">1</span> <span class="op">==</span> <span class="dv">0</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> ( <span class="dv">1</span> <span class="op">-</span><span class="dv">1</span>))) <span class="co">-- note sharing!</span></span>
|
||
<span id="cb67-7"><a href="#cb67-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> ( <span class="dt">False</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">1</span><span class="op">-</span><span class="dv">1</span>)))</span>
|
||
<span id="cb67-8"><a href="#cb67-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">1</span><span class="op">-</span><span class="dv">1</span>)))</span>
|
||
<span id="cb67-9"><a href="#cb67-9" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">not</span> ((<span class="dv">1</span><span class="op">-</span><span class="dv">1</span>) <span class="op">==</span> <span class="dv">0</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> ((<span class="dv">1</span><span class="op">-</span><span class="dv">1</span>)<span class="op">-</span><span class="dv">1</span>))))</span>
|
||
<span id="cb67-10"><a href="#cb67-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">not</span> ( <span class="dv">0</span> <span class="op">==</span> <span class="dv">0</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> ( <span class="dv">0</span> <span class="op">-</span><span class="dv">1</span>)))) <span class="co">-- (sharing)</span></span>
|
||
<span id="cb67-11"><a href="#cb67-11" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">not</span> ( <span class="dt">True</span> <span class="op">||</span> <span class="fu">not</span> (<span class="fu">even</span> (<span class="dv">0</span><span class="op">-</span><span class="dv">1</span>))))</span>
|
||
<span id="cb67-12"><a href="#cb67-12" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> (<span class="fu">not</span> <span class="dt">True</span>)</span>
|
||
<span id="cb67-13"><a href="#cb67-13" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">not</span> <span class="dt">False</span></span>
|
||
<span id="cb67-14"><a href="#cb67-14" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">True</span></span></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="cb68"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb68-1"><a href="#cb68-1" aria-hidden="true" tabindex="-1"></a>even' x <span class="ot">=</span> <span class="fu">not</span> (even' (x<span class="op">-</span><span class="dv">1</span>)) <span class="op">||</span> x <span class="op">==</span> <span class="dv">0</span></span></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="cb69"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb69-1"><a href="#cb69-1" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (x<span class="op">:</span>_) <span class="ot">=</span> x</span>
|
||
<span id="cb69-2"><a href="#cb69-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> [] <span class="ot">=</span> <span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb69-3"><a href="#cb69-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb69-4"><a href="#cb69-4" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> p [] <span class="ot">=</span> []</span>
|
||
<span id="cb69-5"><a href="#cb69-5" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> p (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">if</span> p x</span>
|
||
<span id="cb69-6"><a href="#cb69-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> x <span class="op">:</span> <span class="fu">filter</span> p xs</span>
|
||
<span id="cb69-7"><a href="#cb69-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="fu">filter</span> p xs</span>
|
||
<span id="cb69-8"><a href="#cb69-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb69-9"><a href="#cb69-9" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f [] <span class="ot">=</span> []</span>
|
||
<span id="cb69-10"><a href="#cb69-10" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f (x<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> <span class="fu">map</span> f xs</span>
|
||
<span id="cb69-11"><a href="#cb69-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb69-12"><a href="#cb69-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- [0..] is syntax sugar for enumFrom 0</span></span>
|
||
<span id="cb69-13"><a href="#cb69-13" aria-hidden="true" tabindex="-1"></a><span class="fu">enumFrom</span> n <span class="ot">=</span> n <span class="op">:</span> <span class="fu">enumFrom</span> (n<span class="op">+</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>And here we go:</p>
|
||
<div class="sourceCode" id="cb70"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb70-1"><a href="#cb70-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) (<span class="fu">enumFrom</span> <span class="dv">0</span>)))</span>
|
||
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces filter, which forces map, which forces enumFrom. We apply the definition of enumFrom.</span></span>
|
||
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) (<span class="dv">0</span><span class="op">:</span>[<span class="dv">1</span><span class="op">..</span>])))</span>
|
||
<span id="cb70-5"><a href="#cb70-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces filter, which forces map. We apply the second equation of map.</span></span>
|
||
<span id="cb70-6"><a href="#cb70-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) ((<span class="dv">3</span><span class="op">^</span><span class="dv">0</span>) <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-7"><a href="#cb70-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces filter. We apply the second equation of filter</span></span>
|
||
<span id="cb70-8"><a href="#cb70-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> ((<span class="dv">3</span><span class="op">^</span><span class="dv">0</span>)<span class="op">></span><span class="dv">100</span>)</span>
|
||
<span id="cb70-9"><a href="#cb70-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> (<span class="dv">3</span><span class="op">^</span><span class="dv">0</span>) <span class="op">:</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>])</span>
|
||
<span id="cb70-10"><a href="#cb70-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-11"><a href="#cb70-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces if, if forces >, > forces ^. Note sharing!</span></span>
|
||
<span id="cb70-12"><a href="#cb70-12" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> (<span class="dv">1</span><span class="op">></span><span class="dv">100</span>)</span>
|
||
<span id="cb70-13"><a href="#cb70-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>])</span>
|
||
<span id="cb70-14"><a href="#cb70-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-15"><a href="#cb70-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces if, if forces ></span></span>
|
||
<span id="cb70-16"><a href="#cb70-16" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> <span class="dt">False</span></span>
|
||
<span id="cb70-17"><a href="#cb70-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>])</span>
|
||
<span id="cb70-18"><a href="#cb70-18" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-19"><a href="#cb70-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- apply definition of if</span></span>
|
||
<span id="cb70-20"><a href="#cb70-20" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">1</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-21"><a href="#cb70-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- let's take slightly bigger steps now</span></span>
|
||
<span id="cb70-22"><a href="#cb70-22" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) (<span class="dv">1</span><span class="op">:</span>[<span class="dv">2</span><span class="op">..</span>])))</span>
|
||
<span id="cb70-23"><a href="#cb70-23" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) ((<span class="dv">3</span><span class="op">^</span><span class="dv">1</span>) <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">2</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-24"><a href="#cb70-24" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">3</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">2</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-25"><a href="#cb70-25" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">2</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-26"><a href="#cb70-26" aria-hidden="true" tabindex="-1"></a><span class="co">-- and even bigger steps now</span></span>
|
||
<span id="cb70-27"><a href="#cb70-27" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">9</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">3</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-28"><a href="#cb70-28" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">27</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">4</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-29"><a href="#cb70-29" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">81</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">5</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-30"><a href="#cb70-30" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="dv">243</span> <span class="op">:</span> <span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">6</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-31"><a href="#cb70-31" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="dv">243</span> <span class="op">:</span> <span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (<span class="dv">3</span><span class="op">^</span>) [<span class="dv">6</span><span class="op">..</span>]))</span>
|
||
<span id="cb70-32"><a href="#cb70-32" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">243</span></span></code></pre></div>
|
||
<p>Whew.</p>
|
||
<h2 data-number="10.5" 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="cb71"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb71-1"><a href="#cb71-1" aria-hidden="true" tabindex="-1"></a><span class="ot">everySecond ::</span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb71-2"><a href="#cb71-2" aria-hidden="true" tabindex="-1"></a>everySecond [] <span class="ot">=</span> []</span>
|
||
<span id="cb71-3"><a href="#cb71-3" aria-hidden="true" tabindex="-1"></a>everySecond (x<span class="op">:</span>y<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">:</span> everySecond xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb72"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb72-1"><a href="#cb72-1" aria-hidden="true" tabindex="-1"></a><span class="fu">take</span> <span class="dv">10</span> (everySecond [<span class="dv">0</span><span class="op">..</span>]) <span class="op">==></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>]</span></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="cb73"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb73-1"><a href="#cb73-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span><span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb73-2"><a href="#cb73-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb73-3"><a href="#cb73-3" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f (x<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> <span class="fu">map</span> f xs</span>
|
||
<span id="cb73-4"><a href="#cb73-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb73-5"><a href="#cb73-5" aria-hidden="true" tabindex="-1"></a><span class="ot">mapTailRecursive ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb73-6"><a href="#cb73-6" aria-hidden="true" tabindex="-1"></a>mapTailRecursive f xs <span class="ot">=</span> go xs []</span>
|
||
<span id="cb73-7"><a href="#cb73-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go (x<span class="op">:</span>xs) res <span class="ot">=</span> go xs (res<span class="op">++</span>[f x])</span>
|
||
<span id="cb73-8"><a href="#cb73-8" aria-hidden="true" tabindex="-1"></a> go [] res <span class="ot">=</span> res</span></code></pre></div>
|
||
<div class="sourceCode" id="cb74"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb74-1"><a href="#cb74-1" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">map</span> <span class="fu">succ</span> [<span class="dv">0</span><span class="op">..</span>]) <span class="op">==></span> <span class="fu">head</span> (<span class="fu">succ</span> <span class="dv">0</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">succ</span> [<span class="dv">1</span><span class="op">..</span>]) <span class="op">==></span> <span class="fu">succ</span> <span class="dv">0</span> <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb74-2"><a href="#cb74-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (mapTailRecursive <span class="fu">succ</span> [<span class="dv">0</span><span class="op">..</span>])</span>
|
||
<span id="cb74-3"><a href="#cb74-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (go [<span class="dv">0</span><span class="op">..</span>] [])</span>
|
||
<span id="cb74-4"><a href="#cb74-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (go [<span class="dv">1</span><span class="op">..</span>] ([]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">0</span>]))</span>
|
||
<span id="cb74-5"><a href="#cb74-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (go [<span class="dv">2</span><span class="op">..</span>] ([]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">0</span>]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">1</span>]))</span>
|
||
<span id="cb74-6"><a href="#cb74-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (go [<span class="dv">3</span><span class="op">..</span>] ([]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">0</span>]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">1</span>]<span class="op">++</span>[<span class="fu">succ</span> <span class="dv">2</span>]))</span>
|
||
<span id="cb74-7"><a href="#cb74-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- never terminates</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb75"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb75-1"><a href="#cb75-1" aria-hidden="true" tabindex="-1"></a><span class="fu">drop</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb75-2"><a href="#cb75-2" aria-hidden="true" tabindex="-1"></a><span class="fu">drop</span> <span class="dv">0</span> xs <span class="ot">=</span> xs</span>
|
||
<span id="cb75-3"><a href="#cb75-3" aria-hidden="true" tabindex="-1"></a><span class="fu">drop</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb75-4"><a href="#cb75-4" aria-hidden="true" tabindex="-1"></a><span class="fu">drop</span> n (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="fu">drop</span> (n<span class="op">-</span><span class="dv">1</span>) xs</span>
|
||
<span id="cb75-5"><a href="#cb75-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb75-6"><a href="#cb75-6" aria-hidden="true" tabindex="-1"></a><span class="ot">myDrop ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb75-7"><a href="#cb75-7" aria-hidden="true" tabindex="-1"></a>myDrop <span class="dv">0</span> xs <span class="ot">=</span> xs</span>
|
||
<span id="cb75-8"><a href="#cb75-8" aria-hidden="true" tabindex="-1"></a>myDrop n xs <span class="ot">=</span> <span class="kw">if</span> n <span class="op">></span> <span class="fu">length</span> xs <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="op">-</span><span class="dv">1</span>) (<span class="fu">tail</span> xs)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb76"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb76-1"><a href="#cb76-1" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">drop</span> <span class="dv">2</span> [<span class="dv">0</span><span class="op">..</span>]) <span class="op">==></span> <span class="fu">head</span> (<span class="fu">drop</span> <span class="dv">1</span> [<span class="dv">1</span><span class="op">..</span>]) <span class="op">==></span> <span class="fu">head</span> (<span class="fu">drop</span> <span class="dv">0</span> [<span class="dv">2</span><span class="op">..</span>]) <span class="op">==></span> <span class="fu">head</span> [<span class="dv">2</span><span class="op">..</span>] <span class="op">==></span> <span class="dv">2</span></span>
|
||
<span id="cb76-2"><a href="#cb76-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (myDrop <span class="dv">2</span> [<span class="dv">0</span><span class="op">..</span>])</span>
|
||
<span id="cb76-3"><a href="#cb76-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> n <span class="op">></span> <span class="fu">length</span> [<span class="dv">0</span><span class="op">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="op">-</span><span class="dv">1</span>) (<span class="fu">tail</span> [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb76-4"><a href="#cb76-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> n <span class="op">></span> <span class="dv">1</span><span class="op">+</span><span class="fu">length</span> [<span class="dv">1</span><span class="op">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="op">-</span><span class="dv">1</span>) (<span class="fu">tail</span> [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb76-5"><a href="#cb76-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> n <span class="op">></span> <span class="dv">1</span><span class="op">+</span><span class="dv">1</span><span class="op">+</span><span class="fu">length</span> [<span class="dv">2</span><span class="op">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="op">-</span><span class="dv">1</span>) (<span class="fu">tail</span> [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb76-6"><a href="#cb76-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">head</span> (<span class="kw">if</span> n <span class="op">></span> <span class="dv">1</span><span class="op">+</span><span class="dv">1</span><span class="op">+</span><span class="dv">1</span><span class="op">+</span><span class="fu">length</span> [<span class="dv">3</span><span class="op">..</span>] <span class="kw">then</span> [] <span class="kw">else</span> myDrop (n<span class="op">-</span><span class="dv">1</span>) (<span class="fu">tail</span> [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb76-7"><a href="#cb76-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- never terminates</span></span></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="cb77"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb77-1"><a href="#cb77-1" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">takeWhile</span> (<span class="op">>=</span><span class="dv">0</span>) [<span class="dv">0</span><span class="op">..</span>]) <span class="op">==></span> <span class="dv">0</span></span>
|
||
<span id="cb77-2"><a href="#cb77-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">concat</span> (<span class="fu">repeat</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])) <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb77-3"><a href="#cb77-3" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">zip</span> [<span class="dv">0</span><span class="op">..</span>] [<span class="dv">2</span><span class="op">..</span>]) <span class="op">==></span> (<span class="dv">0</span>,<span class="dv">2</span>)</span>
|
||
<span id="cb77-4"><a href="#cb77-4" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">filter</span> <span class="fu">even</span> [<span class="dv">3</span><span class="op">..</span>]) <span class="op">==></span> <span class="dv">4</span></span></code></pre></div>
|
||
<h2 data-number="10.6" 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="cb78"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb78-1"><a href="#cb78-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="dv">1</span><span class="op">+</span>(<span class="dv">2</span><span class="op">+</span>(<span class="dv">3</span><span class="op">+</span><span class="dv">0</span>))</span>
|
||
<span id="cb78-2"><a href="#cb78-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldl</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> ((<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>)<span class="op">+</span><span class="dv">2</span>)<span class="op">+</span><span class="dv">3</span></span></code></pre></div>
|
||
<p>Here are the definitions of <code>foldl</code> and
|
||
<code>foldr</code>:</p>
|
||
<div class="sourceCode" id="cb79"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb79-1"><a href="#cb79-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldl</span><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</span>
|
||
<span id="cb79-2"><a href="#cb79-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldl</span> f z [] <span class="ot">=</span> z</span>
|
||
<span id="cb79-3"><a href="#cb79-3" aria-hidden="true" tabindex="-1"></a><span class="fu">foldl</span> f z (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="fu">foldl</span> f (f z x) xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb80"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb80-1"><a href="#cb80-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span><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</span>
|
||
<span id="cb80-2"><a href="#cb80-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> f y [] <span class="ot">=</span> y</span>
|
||
<span id="cb80-3"><a href="#cb80-3" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> f y (x<span class="op">:</span>xs) <span class="ot">=</span> f x (<span class="fu">foldr</span> f y xs)</span></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="cb81"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb81-1"><a href="#cb81-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">foldr</span> (<span class="op">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb81-2"><a href="#cb81-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">False</span> <span class="op">&&</span> (<span class="fu">foldr</span> (<span class="op">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>])</span>
|
||
<span id="cb81-3"><a href="#cb81-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">False</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb82"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb82-1"><a href="#cb82-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">head</span> (<span class="fu">foldr</span> (<span class="op">++</span>) [] [<span class="st">"Hello"</span>,<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</span>
|
||
<span id="cb82-2"><a href="#cb82-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="st">"Hello"</span> <span class="op">++</span> (<span class="fu">foldr</span> (<span class="op">++</span>) [] [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>]))</span>
|
||
<span id="cb82-3"><a href="#cb82-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="ch">'H'</span><span class="op">:</span>(<span class="st">"ello"</span> <span class="op">++</span> (<span class="fu">foldr</span> (<span class="op">++</span>) [] [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])))</span>
|
||
<span id="cb82-4"><a href="#cb82-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="ch">'H'</span></span></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="cb83"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb83-1"><a href="#cb83-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">foldl</span> (<span class="op">&&</span>) <span class="dt">True</span> [<span class="dt">False</span>,<span class="dt">False</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb83-2"><a href="#cb83-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">&&</span>) (<span class="dt">True</span><span class="op">&&</span><span class="dt">False</span>) [<span class="dt">False</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb83-3"><a href="#cb83-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">&&</span>) ((<span class="dt">True</span><span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span>) [<span class="dt">False</span>]</span>
|
||
<span id="cb83-4"><a href="#cb83-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">&&</span>) (((<span class="dt">True</span><span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span>) []</span>
|
||
<span id="cb83-5"><a href="#cb83-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> ((<span class="dt">True</span><span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span></span>
|
||
<span id="cb83-6"><a href="#cb83-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> ( <span class="dt">False</span> <span class="op">&&</span><span class="dt">False</span>)<span class="op">&&</span><span class="dt">False</span></span>
|
||
<span id="cb83-7"><a href="#cb83-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">False</span> <span class="op">&&</span><span class="dt">False</span></span>
|
||
<span id="cb83-8"><a href="#cb83-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">False</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb84"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb84-1"><a href="#cb84-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">head</span> (<span class="fu">foldl</span> (<span class="op">++</span>) [] [<span class="st">"Hello"</span>,<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</span>
|
||
<span id="cb84-2"><a href="#cb84-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">foldl</span> (<span class="op">++</span>) ([]<span class="op">++</span><span class="st">"Hello"</span>) [<span class="st">"World"</span>,<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</span>
|
||
<span id="cb84-3"><a href="#cb84-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">foldl</span> (<span class="op">++</span>) (([]<span class="op">++</span><span class="st">"Hello"</span>)<span class="op">++</span><span class="st">"World"</span>) [<span class="st">"lorem"</span>,<span class="st">"ipsum"</span>])</span>
|
||
<span id="cb84-4"><a href="#cb84-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">foldl</span> (<span class="op">++</span>) ((([]<span class="op">++</span><span class="st">"Hello"</span>)<span class="op">++</span><span class="st">"World"</span>)<span class="op">++</span><span class="st">"lorem"</span>) [<span class="st">"ipsum"</span>])</span>
|
||
<span id="cb84-5"><a href="#cb84-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="fu">foldl</span> (<span class="op">++</span>) (((([]<span class="op">++</span><span class="st">"Hello"</span>)<span class="op">++</span><span class="st">"World"</span>)<span class="op">++</span><span class="st">"lorem"</span>)<span class="op">++</span><span class="st">"ipsum"</span>) [])</span>
|
||
<span id="cb84-6"><a href="#cb84-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (((([]<span class="op">++</span><span class="st">"Hello"</span>)<span class="op">++</span><span class="st">"World"</span>)<span class="op">++</span><span class="st">"lorem"</span>)<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-7"><a href="#cb84-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- head forces the last ++, which forces the next-to-last ++, and so on</span></span>
|
||
<span id="cb84-8"><a href="#cb84-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (((<span class="st">"Hello"</span><span class="op">++</span><span class="st">"World"</span>)<span class="op">++</span><span class="st">"lorem"</span>)<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-9"><a href="#cb84-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- same happens again</span></span>
|
||
<span id="cb84-10"><a href="#cb84-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (((<span class="ch">'H'</span><span class="op">:</span>(<span class="st">"ello"</span><span class="op">++</span><span class="st">"World"</span>))<span class="op">++</span><span class="st">"lorem"</span>)<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-11"><a href="#cb84-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- for clarity, let's drop the "ello"++"World" expression which isn't needed</span></span>
|
||
<span id="cb84-12"><a href="#cb84-12" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (((<span class="ch">'H'</span><span class="op">:</span>__)<span class="op">++</span><span class="st">"lorem"</span>)<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-13"><a href="#cb84-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- now the next-to-last ++ can operate</span></span>
|
||
<span id="cb84-14"><a href="#cb84-14" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> ((<span class="ch">'H'</span><span class="op">:</span>(__<span class="op">++</span><span class="st">"lorem"</span>))<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-15"><a href="#cb84-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- let's drop the __++"lorem" expression</span></span>
|
||
<span id="cb84-16"><a href="#cb84-16" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> ((<span class="ch">'H'</span><span class="op">:</span>__)<span class="op">++</span><span class="st">"ipsum"</span>)</span>
|
||
<span id="cb84-17"><a href="#cb84-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- now the last ++ can operate</span></span>
|
||
<span id="cb84-18"><a href="#cb84-18" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">head</span> (<span class="ch">'H'</span><span class="op">:</span>(__<span class="op">++</span><span class="st">"ipsum"</span>))</span>
|
||
<span id="cb84-19"><a href="#cb84-19" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="ch">'H'</span></span></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="cb85"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb85-1"><a href="#cb85-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb85-2"><a href="#cb85-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb85-3"><a href="#cb85-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">2</span> <span class="op">+</span> <span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">3</span>])</span>
|
||
<span id="cb85-4"><a href="#cb85-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">2</span> <span class="op">+</span> (<span class="dv">3</span> <span class="op">+</span> <span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> []))</span>
|
||
<span id="cb85-5"><a href="#cb85-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">2</span> <span class="op">+</span> (<span class="dv">3</span> <span class="op">+</span> <span class="dv">0</span>))</span>
|
||
<span id="cb85-6"><a href="#cb85-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">2</span> <span class="op">+</span> <span class="dv">3</span>)</span>
|
||
<span id="cb85-7"><a href="#cb85-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">5</span></span>
|
||
<span id="cb85-8"><a href="#cb85-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">6</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb86"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb86-1"><a href="#cb86-1" aria-hidden="true" tabindex="-1"></a> <span class="fu">foldl</span> (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb86-2"><a href="#cb86-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">+</span>) (<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb86-3"><a href="#cb86-3" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">+</span>) ((<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>)<span class="op">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</span>
|
||
<span id="cb86-4"><a href="#cb86-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">foldl</span> (<span class="op">+</span>) (((<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>)<span class="op">+</span><span class="dv">2</span>)<span class="op">+</span><span class="dv">3</span>) []</span>
|
||
<span id="cb86-5"><a href="#cb86-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> ((<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>)<span class="op">+</span><span class="dv">2</span>)<span class="op">+</span><span class="dv">3</span></span>
|
||
<span id="cb86-6"><a href="#cb86-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> ( <span class="dv">1</span> <span class="op">+</span><span class="dv">2</span>)<span class="op">+</span><span class="dv">3</span></span>
|
||
<span id="cb86-7"><a href="#cb86-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">3</span> <span class="op">+</span><span class="dv">3</span></span>
|
||
<span id="cb86-8"><a href="#cb86-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">6</span></span></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="cb87"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb87-1"><a href="#cb87-1" aria-hidden="true" tabindex="-1"></a> foldl' (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb87-2"><a href="#cb87-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) (<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb87-3"><a href="#cb87-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- force second argument</span></span>
|
||
<span id="cb87-4"><a href="#cb87-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb87-5"><a href="#cb87-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) (<span class="dv">1</span><span class="op">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</span>
|
||
<span id="cb87-6"><a href="#cb87-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- force second argument</span></span>
|
||
<span id="cb87-7"><a href="#cb87-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb87-8"><a href="#cb87-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) (<span class="dv">3</span><span class="op">+</span><span class="dv">3</span>) []</span>
|
||
<span id="cb87-9"><a href="#cb87-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- force second argument</span></span>
|
||
<span id="cb87-10"><a href="#cb87-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">6</span> []</span>
|
||
<span id="cb87-11"><a href="#cb87-11" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">6</span></span></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="cb88"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb88-1"><a href="#cb88-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb88-2"><a href="#cb88-2" aria-hidden="true" tabindex="-1"></a>foldl'Int f z [] <span class="ot">=</span> z</span>
|
||
<span id="cb88-3"><a href="#cb88-3" aria-hidden="true" tabindex="-1"></a>foldl'Int f <span class="dv">0</span> (x<span class="op">:</span>xs) <span class="ot">=</span> foldl'Int f (f <span class="dv">0</span> x) xs</span>
|
||
<span id="cb88-4"><a href="#cb88-4" aria-hidden="true" tabindex="-1"></a>foldl'Int f z (x<span class="op">:</span>xs) <span class="ot">=</span> foldl'Int f (f z x) xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb89"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb89-1"><a href="#cb89-1" aria-hidden="true" tabindex="-1"></a> foldl'Int (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb89-2"><a href="#cb89-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl'Int (<span class="op">+</span>) (<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb89-3"><a href="#cb89-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- to be able to pick between the second and third equations, (0+1) is forced</span></span>
|
||
<span id="cb89-4"><a href="#cb89-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl'Int (<span class="op">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb89-5"><a href="#cb89-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- the third equation applies</span></span>
|
||
<span id="cb89-6"><a href="#cb89-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl'Int (<span class="op">+</span>) (<span class="dv">1</span><span class="op">+</span><span class="dv">2</span>) [<span class="dv">3</span>]</span>
|
||
<span id="cb89-7"><a href="#cb89-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- again, we need to pick between the second and third equations</span></span>
|
||
<span id="cb89-8"><a href="#cb89-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl'Int (<span class="op">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb89-9"><a href="#cb89-9" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl'Int (<span class="op">+</span>) (<span class="dv">3</span><span class="op">+</span><span class="dv">3</span>) []</span>
|
||
<span id="cb89-10"><a href="#cb89-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">3</span><span class="op">+</span><span class="dv">3</span></span>
|
||
<span id="cb89-11"><a href="#cb89-11" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">6</span></span></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="cb90"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">seq</span> (<span class="fu">not</span> <span class="dt">True</span>) <span class="dv">3</span></span>
|
||
<span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">seq</span> <span class="fu">undefined</span> <span class="dv">3</span></span>
|
||
<span id="cb90-4"><a href="#cb90-4" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> Prelude.undefined</span>
|
||
<span id="cb90-5"><a href="#cb90-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (<span class="fu">seq</span> (<span class="fu">not</span> <span class="dt">True</span>) <span class="dv">3</span>) <span class="op">+</span> <span class="dv">7</span></span>
|
||
<span id="cb90-6"><a href="#cb90-6" aria-hidden="true" tabindex="-1"></a><span class="dv">10</span></span>
|
||
<span id="cb90-7"><a href="#cb90-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (<span class="fu">seq</span> <span class="fu">undefined</span> <span class="dv">3</span>) <span class="op">+</span> <span class="dv">7</span></span>
|
||
<span id="cb90-8"><a href="#cb90-8" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> Prelude.undefined</span>
|
||
<span id="cb90-9"><a href="#cb90-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">let</span> f x <span class="ot">=</span> f x <span class="kw">in</span> <span class="fu">seq</span> (f <span class="dv">3</span>) <span class="dv">3</span></span>
|
||
<span id="cb90-10"><a href="#cb90-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...infinite recursion</span></span></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="cb91"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb91-1"><a href="#cb91-1" aria-hidden="true" tabindex="-1"></a><span class="ot">strictHead ::</span> [a] <span class="ot">-></span> a</span>
|
||
<span id="cb91-2"><a href="#cb91-2" aria-hidden="true" tabindex="-1"></a>strictHead xs <span class="ot">=</span> <span class="fu">seq</span> (<span class="fu">last</span> xs) (<span class="fu">head</span> xs)</span></code></pre></div>
|
||
<p>Let’s play around with it in GHCi:</p>
|
||
<div class="sourceCode" id="cb92"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb92-1"><a href="#cb92-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">head</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb92-2"><a href="#cb92-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb92-3"><a href="#cb92-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> strictHead [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb92-4"><a href="#cb92-4" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb92-5"><a href="#cb92-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">head</span> (<span class="dv">1</span><span class="op">:</span><span class="dv">2</span><span class="op">:</span><span class="fu">undefined</span>)</span>
|
||
<span id="cb92-6"><a href="#cb92-6" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb92-7"><a href="#cb92-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> strictHead (<span class="dv">1</span><span class="op">:</span><span class="dv">2</span><span class="op">:</span><span class="fu">undefined</span>)</span>
|
||
<span id="cb92-8"><a href="#cb92-8" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> Prelude.undefined</span>
|
||
<span id="cb92-9"><a href="#cb92-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">head</span> [<span class="dv">1</span><span class="op">..</span>]</span>
|
||
<span id="cb92-10"><a href="#cb92-10" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb92-11"><a href="#cb92-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> strictHead [<span class="dv">1</span><span class="op">..</span>]</span>
|
||
<span id="cb92-12"><a href="#cb92-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- ...infinite recursion</span></span></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="cb93"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb93-1"><a href="#cb93-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb93-2"><a href="#cb93-2" aria-hidden="true" tabindex="-1"></a>foldl' f z [] <span class="ot">=</span> z</span>
|
||
<span id="cb93-3"><a href="#cb93-3" aria-hidden="true" tabindex="-1"></a>foldl' f z (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">let</span> z' <span class="ot">=</span> f z x</span>
|
||
<span id="cb93-4"><a href="#cb93-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">seq</span> z' (foldl' f z' xs)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb94"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb94-1"><a href="#cb94-1" aria-hidden="true" tabindex="-1"></a> foldl' (<span class="op">+</span>) <span class="dv">0</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb94-2"><a href="#cb94-2" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> (<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>) (foldl' (<span class="op">+</span>) (<span class="dv">0</span><span class="op">+</span><span class="dv">1</span>) [<span class="dv">2</span>,<span class="dv">3</span>]) <span class="co">-- seq forces first argument</span></span>
|
||
<span id="cb94-3"><a href="#cb94-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">|</span></span>
|
||
<span id="cb94-4"><a href="#cb94-4" aria-hidden="true" tabindex="-1"></a> <span class="op">+-----</span>sharing<span class="co">-----'</span></span>
|
||
<span id="cb94-5"><a href="#cb94-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="op">|</span></span>
|
||
<span id="cb94-6"><a href="#cb94-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> <span class="dv">1</span> (foldl' (<span class="op">+</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></span>
|
||
<span id="cb94-7"><a href="#cb94-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">1</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb94-8"><a href="#cb94-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> (<span class="dv">1</span><span class="op">+</span><span class="dv">2</span>) (foldl' (<span class="op">+</span>) (<span class="dv">1</span><span class="op">+</span><span class="dv">2</span>) [<span class="dv">3</span>])</span>
|
||
<span id="cb94-9"><a href="#cb94-9" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> <span class="dv">3</span> (foldl' (<span class="op">+</span>) <span class="dv">3</span> [<span class="dv">3</span>])</span>
|
||
<span id="cb94-10"><a href="#cb94-10" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">3</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb94-11"><a href="#cb94-11" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> (<span class="dv">3</span><span class="op">+</span><span class="dv">3</span>) (foldl' (<span class="op">+</span>) (<span class="dv">3</span><span class="op">+</span><span class="dv">3</span>) [])</span>
|
||
<span id="cb94-12"><a href="#cb94-12" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="fu">seq</span> <span class="dv">6</span> (foldl' (<span class="op">+</span>) <span class="dv">6</span> [])</span>
|
||
<span id="cb94-13"><a href="#cb94-13" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> foldl' (<span class="op">+</span>) <span class="dv">6</span> []</span>
|
||
<span id="cb94-14"><a href="#cb94-14" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dv">6</span></span></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="https://book.realworldhaskell.org/read/profiling-and-optimization.html">Real
|
||
World Haskell</a>.</p>
|
||
<h2 data-number="10.7" 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="cb95"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb95-1"><a href="#cb95-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></span></code></pre></div>
|
||
<p>However, the following won’t work, you need <code>data</code>:</p>
|
||
<div class="sourceCode" id="cb96"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb96-1"><a href="#cb96-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- the compiler won't accept these!</span></span>
|
||
<span id="cb96-2"><a href="#cb96-2" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Currency</span> <span class="ot">=</span> <span class="dt">Dollars</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Euros</span> <span class="dt">Int</span></span>
|
||
<span id="cb96-3"><a href="#cb96-3" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Money</span> <span class="dt">Int</span> <span class="dt">Int</span></span></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="cb97"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb97-1"><a href="#cb97-1" aria-hidden="true" tabindex="-1"></a>code<span class="op">:</span> memory<span class="op">:</span></span>
|
||
<span id="cb97-2"><a href="#cb97-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb97-3"><a href="#cb97-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Cents</span> <span class="dt">Int</span> x <span class="op">--></span> <span class="dt">Cents</span> <span class="op">--></span> <span class="dv">100</span></span>
|
||
<span id="cb97-4"><a href="#cb97-4" aria-hidden="true" tabindex="-1"></a>x <span class="ot">=</span> <span class="dt">Cents</span> <span class="dv">100</span></span>
|
||
<span id="cb97-5"><a href="#cb97-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb97-6"><a href="#cb97-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb97-7"><a href="#cb97-7" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Cents</span> <span class="dt">Int</span> x <span class="op">--></span> <span class="dv">100</span></span>
|
||
<span id="cb97-8"><a href="#cb97-8" aria-hidden="true" tabindex="-1"></a>x <span class="ot">=</span> <span class="dt">Cents</span> <span class="dv">100</span></span></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="cb98"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb98-1"><a href="#cb98-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- if we use data, Cents undefined is in WHNF</span></span>
|
||
<span id="cb98-2"><a href="#cb98-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">data</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></span>
|
||
<span id="cb98-3"><a href="#cb98-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">seq</span> (<span class="dt">Cents</span> <span class="fu">undefined</span>) <span class="dt">True</span></span>
|
||
<span id="cb98-4"><a href="#cb98-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb98-5"><a href="#cb98-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- if we use newtype, Cents undefined isn't in WHNF, and trying</span></span>
|
||
<span id="cb98-6"><a href="#cb98-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- to make it so trips up in undefined</span></span>
|
||
<span id="cb98-7"><a href="#cb98-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">newtype</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Cents</span> <span class="dt">Int</span></span>
|
||
<span id="cb98-8"><a href="#cb98-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">seq</span> (<span class="dt">Cents</span> <span class="fu">undefined</span>) <span class="dt">True</span></span>
|
||
<span id="cb98-9"><a href="#cb98-9" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> Prelude.undefined</span></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="cb99"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb99-1"><a href="#cb99-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Inverted</span> <span class="ot">=</span> <span class="dt">Inverted</span> <span class="dt">Int</span></span>
|
||
<span id="cb99-2"><a href="#cb99-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb99-3"><a href="#cb99-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb99-4"><a href="#cb99-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Ord</span> <span class="dt">Inverted</span> <span class="kw">where</span></span>
|
||
<span id="cb99-5"><a href="#cb99-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">compare</span> (<span class="dt">Inverted</span> i) (<span class="dt">Inverted</span> j) <span class="ot">=</span> <span class="fu">compare</span> j i</span></code></pre></div>
|
||
<div class="sourceCode" id="cb100"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb100-1"><a href="#cb100-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="op">></span> <span class="fu">sort</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb100-2"><a href="#cb100-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb100-3"><a href="#cb100-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="op">></span> <span class="fu">sort</span> [<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>]</span>
|
||
<span id="cb100-4"><a href="#cb100-4" aria-hidden="true" tabindex="-1"></a>[<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>]</span></code></pre></div>
|
||
<h2 data-number="10.8" 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="cb101"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb101-1"><a href="#cb101-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">take</span> <span class="dv">21</span> <span class="op">$</span> <span class="fu">cycle</span> <span class="st">"asdf"</span></span>
|
||
<span id="cb101-2"><a href="#cb101-2" aria-hidden="true" tabindex="-1"></a><span class="st">"asdfasdfasdfasdfasdfa"</span></span></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="cb102"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb102-1"><a href="#cb102-1" aria-hidden="true" tabindex="-1"></a> code memory</span>
|
||
<span id="cb102-2"><a href="#cb102-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb102-3"><a href="#cb102-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> xs <span class="ot">=</span> <span class="dv">1</span><span class="op">:</span><span class="dv">2</span><span class="op">:</span>xs xs <span class="ot">-></span> (<span class="dv">1</span><span class="op">:</span>) <span class="ot">-></span> (<span class="dv">2</span><span class="op">:</span>) <span class="op">-+</span></span>
|
||
<span id="cb102-4"><a href="#cb102-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> xs <span class="op">^</span> <span class="op">|</span></span>
|
||
<span id="cb102-5"><a href="#cb102-5" aria-hidden="true" tabindex="-1"></a> <span class="op">+------------+</span></span></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="cb103"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb103-1"><a href="#cb103-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Room</span> <span class="ot">=</span> <span class="dt">Room</span> <span class="dt">String</span> [(<span class="dt">String</span>,<span class="dt">Room</span>)]</span>
|
||
<span id="cb103-2"><a href="#cb103-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb103-3"><a href="#cb103-3" aria-hidden="true" tabindex="-1"></a><span class="ot">describe ::</span> <span class="dt">Room</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb103-4"><a href="#cb103-4" aria-hidden="true" tabindex="-1"></a>describe (<span class="dt">Room</span> s _) <span class="ot">=</span> s</span>
|
||
<span id="cb103-5"><a href="#cb103-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb103-6"><a href="#cb103-6" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb103-7"><a href="#cb103-7" aria-hidden="true" tabindex="-1"></a>move (<span class="dt">Room</span> _ directions) direction <span class="ot">=</span> <span class="fu">lookup</span> direction directions</span>
|
||
<span id="cb103-8"><a href="#cb103-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb103-9"><a href="#cb103-9" aria-hidden="true" tabindex="-1"></a><span class="ot">world ::</span> <span class="dt">Room</span></span>
|
||
<span id="cb103-10"><a href="#cb103-10" aria-hidden="true" tabindex="-1"></a>world <span class="ot">=</span> meadow</span>
|
||
<span id="cb103-11"><a href="#cb103-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span>
|
||
<span id="cb103-12"><a href="#cb103-12" aria-hidden="true" tabindex="-1"></a> meadow <span class="ot">=</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)]</span>
|
||
<span id="cb103-13"><a href="#cb103-13" aria-hidden="true" tabindex="-1"></a> cave <span class="ot">=</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)]</span>
|
||
<span id="cb103-14"><a href="#cb103-14" aria-hidden="true" tabindex="-1"></a> tunnel <span class="ot">=</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></span>
|
||
<span id="cb103-15"><a href="#cb103-15" aria-hidden="true" tabindex="-1"></a> [(<span class="st">"Go back"</span>,cave),(<span class="st">"Go left"</span>,pit),(<span class="st">"Go right"</span>,treasure)]</span>
|
||
<span id="cb103-16"><a href="#cb103-16" aria-hidden="true" tabindex="-1"></a> pit <span class="ot">=</span> <span class="dt">Room</span> <span class="st">"You fall into a pit. There is no way out."</span> []</span>
|
||
<span id="cb103-17"><a href="#cb103-17" aria-hidden="true" tabindex="-1"></a> treasure <span class="ot">=</span> <span class="dt">Room</span> <span class="st">"A green light from a terminal fills the room. The terminal says <<loop>>."</span></span>
|
||
<span id="cb103-18"><a href="#cb103-18" aria-hidden="true" tabindex="-1"></a> [(<span class="st">"Go back"</span>,tunnel)]</span>
|
||
<span id="cb103-19"><a href="#cb103-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb103-20"><a href="#cb103-20" aria-hidden="true" tabindex="-1"></a><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>]</span>
|
||
<span id="cb103-21"><a href="#cb103-21" aria-hidden="true" tabindex="-1"></a>play room [] <span class="ot">=</span> [describe room]</span>
|
||
<span id="cb103-22"><a href="#cb103-22" aria-hidden="true" tabindex="-1"></a>play room (d<span class="op">:</span>ds) <span class="ot">=</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]</span>
|
||
<span id="cb103-23"><a href="#cb103-23" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> r <span class="ot">-></span> describe room <span class="op">:</span> play r ds</span></code></pre></div>
|
||
<div class="sourceCode" id="cb104"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb104-1"><a href="#cb104-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></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>]</span>
|
||
<span id="cb104-2"><a href="#cb104-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">"It's a flowery meadow next to a cliff."</span>,</span>
|
||
<span id="cb104-3"><a href="#cb104-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"It's a flowery meadow next to a cliff."</span>,</span>
|
||
<span id="cb104-4"><a href="#cb104-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"You are in a cave"</span>,</span>
|
||
<span id="cb104-5"><a href="#cb104-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"This is a very dark tunnel. It seems you can either go left or right."</span>,</span>
|
||
<span id="cb104-6"><a href="#cb104-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"You are in a cave"</span>,</span>
|
||
<span id="cb104-7"><a href="#cb104-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"This is a very dark tunnel. It seems you can either go left or right."</span>,</span>
|
||
<span id="cb104-8"><a href="#cb104-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"A green light from a computer terminal floods the room. The terminal says <<loop>>."</span>]</span></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 data-number="10.9" 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="cb106"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb106-1"><a href="#cb106-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Debug.Trace</span></span>
|
||
<span id="cb106-2"><a href="#cb106-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> trace <span class="st">"a"</span> <span class="dt">True</span></span>
|
||
<span id="cb106-3"><a href="#cb106-3" aria-hidden="true" tabindex="-1"></a>a</span>
|
||
<span id="cb106-4"><a href="#cb106-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb106-5"><a href="#cb106-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> trace <span class="st">"a"</span> <span class="dt">False</span> <span class="op">||</span> trace <span class="st">"b"</span> <span class="dt">True</span></span>
|
||
<span id="cb106-6"><a href="#cb106-6" aria-hidden="true" tabindex="-1"></a>a</span>
|
||
<span id="cb106-7"><a href="#cb106-7" aria-hidden="true" tabindex="-1"></a>b</span>
|
||
<span id="cb106-8"><a href="#cb106-8" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb106-9"><a href="#cb106-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> trace <span class="st">"a"</span> <span class="dt">True</span> <span class="op">||</span> trace <span class="st">"b"</span> <span class="dt">True</span></span>
|
||
<span id="cb106-10"><a href="#cb106-10" aria-hidden="true" tabindex="-1"></a>a</span>
|
||
<span id="cb106-11"><a href="#cb106-11" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></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="cb107"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb107-1"><a href="#cb107-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> <span class="fu">head</span> [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>]</span>
|
||
<span id="cb107-2"><a href="#cb107-2" aria-hidden="true" tabindex="-1"></a>first</span>
|
||
<span id="cb107-3"><a href="#cb107-3" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb107-4"><a href="#cb107-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> <span class="fu">last</span> [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>]</span>
|
||
<span id="cb107-5"><a href="#cb107-5" aria-hidden="true" tabindex="-1"></a>third</span>
|
||
<span id="cb107-6"><a href="#cb107-6" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb107-7"><a href="#cb107-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> <span class="fu">length</span> [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>]</span>
|
||
<span id="cb107-8"><a href="#cb107-8" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb107-9"><a href="#cb107-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> <span class="fu">sum</span> [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>]</span>
|
||
<span id="cb107-10"><a href="#cb107-10" aria-hidden="true" tabindex="-1"></a>third</span>
|
||
<span id="cb107-11"><a href="#cb107-11" aria-hidden="true" tabindex="-1"></a>second</span>
|
||
<span id="cb107-12"><a href="#cb107-12" aria-hidden="true" tabindex="-1"></a>first</span>
|
||
<span id="cb107-13"><a href="#cb107-13" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></span></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="cb108"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb108-1"><a href="#cb108-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> <span class="fu">head</span> (<span class="fu">filter</span> (<span class="op">></span><span class="dv">100</span>) (<span class="fu">map</span> (\x <span class="ot">-></span> traceShowId (<span class="dv">3</span><span class="op">^</span>x)) [<span class="dv">0</span><span class="op">..</span>]))</span>
|
||
<span id="cb108-2"><a href="#cb108-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb108-3"><a href="#cb108-3" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb108-4"><a href="#cb108-4" aria-hidden="true" tabindex="-1"></a><span class="dv">9</span></span>
|
||
<span id="cb108-5"><a href="#cb108-5" aria-hidden="true" tabindex="-1"></a><span class="dv">27</span></span>
|
||
<span id="cb108-6"><a href="#cb108-6" aria-hidden="true" tabindex="-1"></a><span class="dv">81</span></span>
|
||
<span id="cb108-7"><a href="#cb108-7" aria-hidden="true" tabindex="-1"></a><span class="dv">243</span></span>
|
||
<span id="cb108-8"><a href="#cb108-8" aria-hidden="true" tabindex="-1"></a><span class="dv">243</span></span></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="cb109"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb109-1"><a href="#cb109-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- computes sums like 7+5+3+1</span></span>
|
||
<span id="cb109-2"><a href="#cb109-2" aria-hidden="true" tabindex="-1"></a><span class="ot">sumEverySecond ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb109-3"><a href="#cb109-3" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">0</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb109-4"><a href="#cb109-4" aria-hidden="true" tabindex="-1"></a>sumEverySecond n <span class="ot">=</span> n <span class="op">+</span> sumEverySecond (n<span class="op">-</span><span class="dv">2</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb110"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb110-1"><a href="#cb110-1" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">6</span> <span class="op">==></span> <span class="dv">12</span></span>
|
||
<span id="cb110-2"><a href="#cb110-2" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">7</span> <span class="op">==></span> doesn't terminate</span></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="cb111"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb111-1"><a href="#cb111-1" aria-hidden="true" tabindex="-1"></a><span class="ot">sumEverySecond ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb111-2"><a href="#cb111-2" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">0</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb111-3"><a href="#cb111-3" aria-hidden="true" tabindex="-1"></a>sumEverySecond n <span class="ot">=</span> trace (<span class="st">"sumEverySecond "</span><span class="op">++</span><span class="fu">show</span> n) (n <span class="op">+</span> sumEverySecond (n<span class="op">-</span><span class="dv">2</span>))</span></code></pre></div>
|
||
<div class="sourceCode" id="cb112"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb112-1"><a href="#cb112-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> sumEverySecond <span class="dv">6</span></span>
|
||
<span id="cb112-2"><a href="#cb112-2" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">6</span></span>
|
||
<span id="cb112-3"><a href="#cb112-3" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">4</span></span>
|
||
<span id="cb112-4"><a href="#cb112-4" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">2</span></span>
|
||
<span id="cb112-5"><a href="#cb112-5" aria-hidden="true" tabindex="-1"></a><span class="dv">12</span></span>
|
||
<span id="cb112-6"><a href="#cb112-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> sumEverySecond <span class="dv">7</span></span>
|
||
<span id="cb112-7"><a href="#cb112-7" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">7</span></span>
|
||
<span id="cb112-8"><a href="#cb112-8" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">5</span></span>
|
||
<span id="cb112-9"><a href="#cb112-9" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">3</span></span>
|
||
<span id="cb112-10"><a href="#cb112-10" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="dv">1</span></span>
|
||
<span id="cb112-11"><a href="#cb112-11" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb112-12"><a href="#cb112-12" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="op">-</span><span class="dv">3</span></span>
|
||
<span id="cb112-13"><a href="#cb112-13" aria-hidden="true" tabindex="-1"></a>sumEverySecond <span class="op">-</span><span class="dv">5</span></span>
|
||
<span id="cb112-14"><a href="#cb112-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- and so on</span></span></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="cb113"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb113-1"><a href="#cb113-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> traceHead xs <span class="ot">=</span> <span class="fu">head</span> (traceShowId xs)</span>
|
||
<span id="cb113-2"><a href="#cb113-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Debug.Trace</span><span class="op">></span> traceHead [<span class="dv">0</span><span class="op">..</span>]</span>
|
||
<span id="cb113-3"><a href="#cb113-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- never terminates since it's trying to show an infinite list</span></span></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 data-number="10.10" 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="cb114"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb114-1"><a href="#cb114-1" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">map</span> <span class="fu">not</span> (<span class="dt">True</span><span class="op">:</span><span class="dt">False</span><span class="op">:</span>[]))</span></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="cb115"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb115-1"><a href="#cb115-1" aria-hidden="true" tabindex="-1"></a>f <span class="dv">0</span> x <span class="ot">=</span> <span class="dv">1</span><span class="op">+</span>x</span>
|
||
<span id="cb115-2"><a href="#cb115-2" aria-hidden="true" tabindex="-1"></a>f _ x <span class="ot">=</span> <span class="dv">2</span><span class="op">+</span>x</span></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="cb116"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb116-1"><a href="#cb116-1" aria-hidden="true" tabindex="-1"></a>f [] <span class="ot">=</span> []</span>
|
||
<span id="cb116-2"><a href="#cb116-2" aria-hidden="true" tabindex="-1"></a>f (x<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">:</span> <span class="fu">map</span> <span class="fu">not</span> xs</span></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="cb117"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb117-1"><a href="#cb117-1" aria-hidden="true" tabindex="-1"></a>f xs <span class="ot">=</span> <span class="fu">map</span> (<span class="op">+</span>(<span class="fu">sum</span> xs)) xs</span></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 data-number="10.11" 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>
|
||
</ul>
|
||
<h1 data-number="11" id="lecture-11-realworld---arealworld"><span
|
||
class="header-section-number">11</span> Lecture 11:
|
||
<code>RealWorld -> (a,RealWorld)</code></h1>
|
||
<h2 data-number="11.1" id="contents"><span
|
||
class="header-section-number">11.1</span> Contents</h2>
|
||
<ul>
|
||
<li>IO</li>
|
||
</ul>
|
||
<h2 data-number="11.2" 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="cb118"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb118-1"><a href="#cb118-1" aria-hidden="true" tabindex="-1"></a>questionnaire <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb118-2"><a href="#cb118-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"Write something!"</span></span>
|
||
<span id="cb118-3"><a href="#cb118-3" aria-hidden="true" tabindex="-1"></a> s <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb118-4"><a href="#cb118-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> (<span class="st">"You wrote: "</span><span class="op">++</span>s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb119"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb119-1"><a href="#cb119-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> questionnaire</span>
|
||
<span id="cb119-2"><a href="#cb119-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Write</span> something<span class="op">!</span></span>
|
||
<span id="cb119-3"><a href="#cb119-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Haskell</span><span class="op">!</span></span>
|
||
<span id="cb119-4"><a href="#cb119-4" aria-hidden="true" tabindex="-1"></a><span class="dt">You</span> wrote<span class="op">:</span> <span class="dt">Haskell</span><span class="op">!</span></span></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="cb120"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb120-1"><a href="#cb120-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.HTTP</span></span>
|
||
<span id="cb120-2"><a href="#cb120-2" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad</span></span>
|
||
<span id="cb120-3"><a href="#cb120-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb120-4"><a href="#cb120-4" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb120-5"><a href="#cb120-5" aria-hidden="true" tabindex="-1"></a> rsp <span class="ot"><-</span> simpleHTTP (getRequest <span class="st">"http://httpbin.org/base64/aGFza2VsbCBmb3IgZXZlcgo="</span>)</span>
|
||
<span id="cb120-6"><a href="#cb120-6" aria-hidden="true" tabindex="-1"></a> body <span class="ot"><-</span> getResponseBody rsp</span>
|
||
<span id="cb120-7"><a href="#cb120-7" aria-hidden="true" tabindex="-1"></a> forM_ (<span class="fu">words</span> body) <span class="op">$</span> \w <span class="ot">-></span> <span class="kw">do</span></span>
|
||
<span id="cb120-8"><a href="#cb120-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStr</span> <span class="st">"word: "</span></span>
|
||
<span id="cb120-9"><a href="#cb120-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> w</span></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="cb122"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb122-1"><a href="#cb122-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">putStrLn</span></span>
|
||
<span id="cb122-2"><a href="#cb122-2" aria-hidden="true" tabindex="-1"></a><span class="fu">putStrLn</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb122-3"><a href="#cb122-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">getLine</span></span>
|
||
<span id="cb122-4"><a href="#cb122-4" aria-hidden="true" tabindex="-1"></a><span class="fu">getLine</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></span></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="cb123"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb123-1"><a href="#cb123-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> operation</span>
|
||
<span id="cb123-2"><a href="#cb123-2" aria-hidden="true" tabindex="-1"></a> operation arg</span>
|
||
<span id="cb123-3"><a href="#cb123-3" aria-hidden="true" tabindex="-1"></a> variable <span class="ot"><-</span> operationThatReturnsStuff</span>
|
||
<span id="cb123-4"><a href="#cb123-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> var2 <span class="ot">=</span> expression</span>
|
||
<span id="cb123-5"><a href="#cb123-5" aria-hidden="true" tabindex="-1"></a> operationThatProducesTheResult var2</span></code></pre></div>
|
||
<h3 data-number="11.2.1" 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.16.4.0/docs/Prelude.html">Prelude</a>
|
||
and <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.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="cb124"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb124-1"><a href="#cb124-1" aria-hidden="true" tabindex="-1"></a><span class="ot">query ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb124-2"><a href="#cb124-2" aria-hidden="true" tabindex="-1"></a>query <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb124-3"><a href="#cb124-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"Write something!"</span> <span class="co">-- run an operation, ignore produced value</span></span>
|
||
<span id="cb124-4"><a href="#cb124-4" aria-hidden="true" tabindex="-1"></a> s <span class="ot"><-</span> <span class="fu">getLine</span> <span class="co">-- run an operation, capture produced value</span></span>
|
||
<span id="cb124-5"><a href="#cb124-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> n <span class="ot">=</span> <span class="fu">length</span> s <span class="co">-- run a pure function</span></span>
|
||
<span id="cb124-6"><a href="#cb124-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> (<span class="st">"You wrote "</span><span class="op">++</span><span class="fu">show</span> n<span class="op">++</span><span class="st">" characters"</span>) <span class="co">-- run an operation, passing on the produced value</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb125"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb125-1"><a href="#cb125-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> query</span>
|
||
<span id="cb125-2"><a href="#cb125-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Write</span> something<span class="op">!</span></span>
|
||
<span id="cb125-3"><a href="#cb125-3" aria-hidden="true" tabindex="-1"></a>lorem ipsum</span>
|
||
<span id="cb125-4"><a href="#cb125-4" aria-hidden="true" tabindex="-1"></a><span class="dt">You</span> wrote <span class="dv">11</span> characters</span></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="cb126"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb126-1"><a href="#cb126-1" aria-hidden="true" tabindex="-1"></a><span class="ot">askForALine ::</span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb126-2"><a href="#cb126-2" aria-hidden="true" tabindex="-1"></a>askForALine <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb126-3"><a href="#cb126-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"Please give me a line"</span></span>
|
||
<span id="cb126-4"><a href="#cb126-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">getLine</span></span></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="cb127"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb127-1"><a href="#cb127-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> askForALine</span>
|
||
<span id="cb127-2"><a href="#cb127-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Please</span> give me a line</span>
|
||
<span id="cb127-3"><a href="#cb127-3" aria-hidden="true" tabindex="-1"></a>this is a line</span>
|
||
<span id="cb127-4"><a href="#cb127-4" aria-hidden="true" tabindex="-1"></a><span class="st">"this is a line"</span></span>
|
||
<span id="cb127-5"><a href="#cb127-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> line <span class="ot"><-</span> askForALine</span>
|
||
<span id="cb127-6"><a href="#cb127-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Please</span> give me a line</span>
|
||
<span id="cb127-7"><a href="#cb127-7" aria-hidden="true" tabindex="-1"></a>this is a line</span>
|
||
<span id="cb127-8"><a href="#cb127-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t line</span>
|
||
<span id="cb127-9"><a href="#cb127-9" aria-hidden="true" tabindex="-1"></a><span class="ot">line ::</span> <span class="dt">String</span></span>
|
||
<span id="cb127-10"><a href="#cb127-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> line</span>
|
||
<span id="cb127-11"><a href="#cb127-11" aria-hidden="true" tabindex="-1"></a><span class="st">"this is a line"</span></span></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="cb128"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb128-1"><a href="#cb128-1" aria-hidden="true" tabindex="-1"></a><span class="ot">ask ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb128-2"><a href="#cb128-2" aria-hidden="true" tabindex="-1"></a>ask question <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb128-3"><a href="#cb128-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> question</span>
|
||
<span id="cb128-4"><a href="#cb128-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">getLine</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb129"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb129-1"><a href="#cb129-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> ask <span class="st">"What is love?"</span></span>
|
||
<span id="cb129-2"><a href="#cb129-2" aria-hidden="true" tabindex="-1"></a><span class="dt">What</span> is love<span class="op">?</span></span>
|
||
<span id="cb129-3"><a href="#cb129-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Baby</span> don't hurt me<span class="op">!</span></span>
|
||
<span id="cb129-4"><a href="#cb129-4" aria-hidden="true" tabindex="-1"></a><span class="st">"Baby don't hurt me!"</span></span>
|
||
<span id="cb129-5"><a href="#cb129-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> response <span class="ot"><-</span> ask <span class="st">"Who are you?"</span></span>
|
||
<span id="cb129-6"><a href="#cb129-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Who</span> are you<span class="op">?</span></span>
|
||
<span id="cb129-7"><a href="#cb129-7" aria-hidden="true" tabindex="-1"></a><span class="dt">The</span> programmer<span class="op">.</span></span>
|
||
<span id="cb129-8"><a href="#cb129-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> response</span>
|
||
<span id="cb129-9"><a href="#cb129-9" aria-hidden="true" tabindex="-1"></a><span class="st">"The programmer."</span></span>
|
||
<span id="cb129-10"><a href="#cb129-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t response</span>
|
||
<span id="cb129-11"><a href="#cb129-11" aria-hidden="true" tabindex="-1"></a><span class="ot">response ::</span> <span class="dt">String</span></span>
|
||
<span id="cb129-12"><a href="#cb129-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t ask</span>
|
||
<span id="cb129-13"><a href="#cb129-13" aria-hidden="true" tabindex="-1"></a><span class="ot">ask ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb129-14"><a href="#cb129-14" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t ask <span class="st">"Who are you?"</span></span>
|
||
<span id="cb129-15"><a href="#cb129-15" aria-hidden="true" tabindex="-1"></a>ask <span class="st">"Who are you?"</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></span></code></pre></div>
|
||
<h2 data-number="11.3" 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="cb130"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb130-1"><a href="#cb130-1" aria-hidden="true" tabindex="-1"></a><span class="ot">produceThree ::</span> <span class="dt">IO</span> <span class="dt">Int</span></span>
|
||
<span id="cb130-2"><a href="#cb130-2" aria-hidden="true" tabindex="-1"></a>produceThree <span class="ot">=</span> <span class="fu">return</span> <span class="dv">3</span></span>
|
||
<span id="cb130-3"><a href="#cb130-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb130-4"><a href="#cb130-4" aria-hidden="true" tabindex="-1"></a><span class="ot">printThree ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb130-5"><a href="#cb130-5" aria-hidden="true" tabindex="-1"></a>printThree <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb130-6"><a href="#cb130-6" aria-hidden="true" tabindex="-1"></a> three <span class="ot"><-</span> produceThree</span>
|
||
<span id="cb130-7"><a href="#cb130-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> (<span class="fu">show</span> three)</span></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="cb131"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb131-1"><a href="#cb131-1" aria-hidden="true" tabindex="-1"></a><span class="ot">yesNoQuestion ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></span>
|
||
<span id="cb131-2"><a href="#cb131-2" aria-hidden="true" tabindex="-1"></a>yesNoQuestion question <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb131-3"><a href="#cb131-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> question</span>
|
||
<span id="cb131-4"><a href="#cb131-4" aria-hidden="true" tabindex="-1"></a> s <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb131-5"><a href="#cb131-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (s <span class="op">==</span> <span class="st">"Y"</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb132"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb132-1"><a href="#cb132-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> yesNoQuestion <span class="st">"Fire the missiles?"</span></span>
|
||
<span id="cb132-2"><a href="#cb132-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Fire</span> the missiles<span class="op">?</span></span>
|
||
<span id="cb132-3"><a href="#cb132-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Y</span></span>
|
||
<span id="cb132-4"><a href="#cb132-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb132-5"><a href="#cb132-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> answer <span class="ot"><-</span> yesNoQuestion <span class="st">"Are you sure?"</span></span>
|
||
<span id="cb132-6"><a href="#cb132-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Are</span> you sure<span class="op">?</span></span>
|
||
<span id="cb132-7"><a href="#cb132-7" aria-hidden="true" tabindex="-1"></a><span class="dt">N</span></span>
|
||
<span id="cb132-8"><a href="#cb132-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t answer</span>
|
||
<span id="cb132-9"><a href="#cb132-9" aria-hidden="true" tabindex="-1"></a><span class="ot">answer ::</span> <span class="dt">Bool</span></span>
|
||
<span id="cb132-10"><a href="#cb132-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> answer</span>
|
||
<span id="cb132-11"><a href="#cb132-11" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></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="cb133"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb133-1"><a href="#cb133-1" aria-hidden="true" tabindex="-1"></a><span class="ot">produceTwo ::</span> <span class="dt">IO</span> <span class="dt">Int</span></span>
|
||
<span id="cb133-2"><a href="#cb133-2" aria-hidden="true" tabindex="-1"></a>produceTwo <span class="ot">=</span> <span class="kw">do</span> <span class="fu">return</span> <span class="dv">1</span></span>
|
||
<span id="cb133-3"><a href="#cb133-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> <span class="dv">2</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb134"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb134-1"><a href="#cb134-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> produceTwo</span>
|
||
<span id="cb134-2"><a href="#cb134-2" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span></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="cb137"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb137-1"><a href="#cb137-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> <span class="op">...</span></span>
|
||
<span id="cb137-2"><a href="#cb137-2" aria-hidden="true" tabindex="-1"></a> x <span class="ot"><-</span> op</span>
|
||
<span id="cb137-3"><a href="#cb137-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> x</span></code></pre></div>
|
||
<div class="sourceCode" id="cb138"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb138-1"><a href="#cb138-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> <span class="op">...</span></span>
|
||
<span id="cb138-2"><a href="#cb138-2" aria-hidden="true" tabindex="-1"></a> op</span></code></pre></div>
|
||
<p>Since <code>return</code> is a function, you should remember to
|
||
parenthesize any complex expressions:</p>
|
||
<div class="sourceCode" id="cb139"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb139-1"><a href="#cb139-1" aria-hidden="true" tabindex="-1"></a><span class="fu">return</span> (f x <span class="op">:</span> xs)</span>
|
||
<span id="cb139-2"><a href="#cb139-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- alternatively:</span></span>
|
||
<span id="cb139-3"><a href="#cb139-3" aria-hidden="true" tabindex="-1"></a><span class="fu">return</span> <span class="op">$</span> f x <span class="op">:</span> xs</span></code></pre></div>
|
||
<h2 data-number="11.4" 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="cb140"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb140-1"><a href="#cb140-1" aria-hidden="true" tabindex="-1"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb140-2"><a href="#cb140-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb140-3"><a href="#cb140-3" aria-hidden="true" tabindex="-1"></a> lastOp</span></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="cb141"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb141-1"><a href="#cb141-1" aria-hidden="true" tabindex="-1"></a>bar x y <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb141-2"><a href="#cb141-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb141-3"><a href="#cb141-3" aria-hidden="true" tabindex="-1"></a> lastOp arg</span></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="cb142"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb142-1"><a href="#cb142-1" aria-hidden="true" tabindex="-1"></a>quux x <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb142-2"><a href="#cb142-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb142-3"><a href="#cb142-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> value</span></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>. It can’t be <code>let foo = bar</code>
|
||
either. 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="cb143"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb143-1"><a href="#cb143-1" aria-hidden="true" tabindex="-1"></a><span class="ot">alwaysFine ::</span> <span class="dt">IO</span> <span class="dt">Bool</span></span>
|
||
<span id="cb143-2"><a href="#cb143-2" aria-hidden="true" tabindex="-1"></a>alwaysFine <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb143-3"><a href="#cb143-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"What?"</span> <span class="co">-- :: IO ()</span></span>
|
||
<span id="cb143-4"><a href="#cb143-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> <span class="dv">2</span> <span class="co">-- :: IO Int, produced value is discarded</span></span>
|
||
<span id="cb143-5"><a href="#cb143-5" aria-hidden="true" tabindex="-1"></a> s <span class="ot"><-</span> <span class="fu">getLine</span> <span class="co">-- getLine :: IO String, thus s :: String</span></span>
|
||
<span id="cb143-6"><a href="#cb143-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> s <span class="co">-- putStrLn :: String -> IO (), thus putStrLn s :: IO ()</span></span>
|
||
<span id="cb143-7"><a href="#cb143-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> b <span class="ot">=</span> <span class="dt">True</span> <span class="co">-- b :: Bool</span></span>
|
||
<span id="cb143-8"><a href="#cb143-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> b <span class="co">-- :: IO Bool</span></span>
|
||
<span id="cb143-9"><a href="#cb143-9" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Thus, alwaysFine :: IO Bool</span></span></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 data-number="11.5" 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="cb144"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb144-1"><a href="#cb144-1" aria-hidden="true" tabindex="-1"></a><span class="fu">print</span><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></span>
|
||
<span id="cb144-2"><a href="#cb144-2" aria-hidden="true" tabindex="-1"></a><span class="fu">readLn</span><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></span></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="cb145"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb145-1"><a href="#cb145-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printDescription ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb145-2"><a href="#cb145-2" aria-hidden="true" tabindex="-1"></a>printDescription n</span>
|
||
<span id="cb145-3"><a href="#cb145-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">even</span> n <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"even"</span></span>
|
||
<span id="cb145-4"><a href="#cb145-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n<span class="op">==</span><span class="dv">3</span> <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"three"</span></span>
|
||
<span id="cb145-5"><a href="#cb145-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">print</span> n</span></code></pre></div>
|
||
<div class="sourceCode" id="cb146"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb146-1"><a href="#cb146-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printDescription <span class="dv">2</span></span>
|
||
<span id="cb146-2"><a href="#cb146-2" aria-hidden="true" tabindex="-1"></a><span class="fu">even</span></span>
|
||
<span id="cb146-3"><a href="#cb146-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printDescription <span class="dv">3</span></span>
|
||
<span id="cb146-4"><a href="#cb146-4" aria-hidden="true" tabindex="-1"></a>three</span>
|
||
<span id="cb146-5"><a href="#cb146-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printDescription <span class="dv">5</span></span>
|
||
<span id="cb146-6"><a href="#cb146-6" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span></span></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="cb147"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb147-1"><a href="#cb147-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb147-2"><a href="#cb147-2" aria-hidden="true" tabindex="-1"></a>printList [] <span class="ot">=</span> <span class="fu">return</span> () <span class="co">-- do nothing</span></span>
|
||
<span id="cb147-3"><a href="#cb147-3" aria-hidden="true" tabindex="-1"></a>printList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> <span class="fu">print</span> x</span>
|
||
<span id="cb147-4"><a href="#cb147-4" aria-hidden="true" tabindex="-1"></a> printList xs <span class="co">-- recursion</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb148"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb148-1"><a href="#cb148-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printList [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb148-2"><a href="#cb148-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb148-3"><a href="#cb148-3" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
|
||
<span id="cb148-4"><a href="#cb148-4" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></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="cb149"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb149-1"><a href="#cb149-1" aria-hidden="true" tabindex="-1"></a><span class="ot">readAndSum ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Int</span></span>
|
||
<span id="cb149-2"><a href="#cb149-2" aria-hidden="true" tabindex="-1"></a>readAndSum <span class="dv">0</span> <span class="ot">=</span> <span class="fu">return</span> <span class="dv">0</span></span>
|
||
<span id="cb149-3"><a href="#cb149-3" aria-hidden="true" tabindex="-1"></a>readAndSum n <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb149-4"><a href="#cb149-4" aria-hidden="true" tabindex="-1"></a> i <span class="ot"><-</span> <span class="fu">readLn</span> <span class="co">-- read one number</span></span>
|
||
<span id="cb149-5"><a href="#cb149-5" aria-hidden="true" tabindex="-1"></a> s <span class="ot"><-</span> readAndSum (n<span class="op">-</span><span class="dv">1</span>) <span class="co">-- recursion: read and sum rest of numbers</span></span>
|
||
<span id="cb149-6"><a href="#cb149-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (i<span class="op">+</span>s) <span class="co">-- produce result</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb150"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb150-1"><a href="#cb150-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> s <span class="ot"><-</span> readAndSum <span class="dv">3</span></span>
|
||
<span id="cb150-2"><a href="#cb150-2" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
|
||
<span id="cb150-3"><a href="#cb150-3" aria-hidden="true" tabindex="-1"></a><span class="dv">4</span></span>
|
||
<span id="cb150-4"><a href="#cb150-4" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span></span>
|
||
<span id="cb150-5"><a href="#cb150-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> s</span>
|
||
<span id="cb150-6"><a href="#cb150-6" aria-hidden="true" tabindex="-1"></a><span class="dv">11</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb151"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb151-1"><a href="#cb151-1" aria-hidden="true" tabindex="-1"></a><span class="ot">ask ::</span> [<span class="dt">String</span>] <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb151-2"><a href="#cb151-2" aria-hidden="true" tabindex="-1"></a>ask [] <span class="ot">=</span> <span class="fu">return</span> []</span>
|
||
<span id="cb151-3"><a href="#cb151-3" aria-hidden="true" tabindex="-1"></a>ask (question<span class="op">:</span>questions) <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb151-4"><a href="#cb151-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStr</span> question</span>
|
||
<span id="cb151-5"><a href="#cb151-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"?"</span></span>
|
||
<span id="cb151-6"><a href="#cb151-6" aria-hidden="true" tabindex="-1"></a> answer <span class="ot"><-</span> <span class="fu">getLine</span> <span class="co">-- get one answer</span></span>
|
||
<span id="cb151-7"><a href="#cb151-7" aria-hidden="true" tabindex="-1"></a> answers <span class="ot"><-</span> ask questions <span class="co">-- recursion: get rest of answers</span></span>
|
||
<span id="cb151-8"><a href="#cb151-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (answer<span class="op">:</span>answers) <span class="co">-- produce result</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb152"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb152-1"><a href="#cb152-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> replies <span class="ot"><-</span> ask [<span class="st">"What is your name"</span>,<span class="st">"How old are you"</span>]</span>
|
||
<span id="cb152-2"><a href="#cb152-2" aria-hidden="true" tabindex="-1"></a><span class="dt">What</span> is your name<span class="op">?</span></span>
|
||
<span id="cb152-3"><a href="#cb152-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Yog</span><span class="op">-</span><span class="dt">Sothoth</span></span>
|
||
<span id="cb152-4"><a href="#cb152-4" aria-hidden="true" tabindex="-1"></a><span class="dt">How</span> old are you<span class="op">?</span></span>
|
||
<span id="cb152-5"><a href="#cb152-5" aria-hidden="true" tabindex="-1"></a><span class="dt">The</span> question is meaningless</span>
|
||
<span id="cb152-6"><a href="#cb152-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> replies</span>
|
||
<span id="cb152-7"><a href="#cb152-7" aria-hidden="true" tabindex="-1"></a>[<span class="st">"Yog-Sothoth"</span>,<span class="st">"The question is meaningless"</span>]</span></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="cb153"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb153-1"><a href="#cb153-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- when b op performs op if b is true</span></span>
|
||
<span id="cb153-2"><a href="#cb153-2" aria-hidden="true" tabindex="-1"></a><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>
|
||
<span id="cb153-3"><a href="#cb153-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- unless b op performs op if b is false</span></span>
|
||
<span id="cb153-4"><a href="#cb153-4" aria-hidden="true" tabindex="-1"></a><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>
|
||
<span id="cb153-5"><a href="#cb153-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- do something many times, collect results</span></span>
|
||
<span id="cb153-6"><a href="#cb153-6" aria-hidden="true" tabindex="-1"></a><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>
|
||
<span id="cb153-7"><a href="#cb153-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- do something many times, throw away the results</span></span>
|
||
<span id="cb153-8"><a href="#cb153-8" aria-hidden="true" tabindex="-1"></a><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>
|
||
<span id="cb153-9"><a href="#cb153-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- do something for every list element</span></span>
|
||
<span id="cb153-10"><a href="#cb153-10" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span><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>
|
||
<span id="cb153-11"><a href="#cb153-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- do something for every list element, throw away the results</span></span>
|
||
<span id="cb153-12"><a href="#cb153-12" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span><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>
|
||
<span id="cb153-13"><a href="#cb153-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- the same, but arguments flipped</span></span>
|
||
<span id="cb153-14"><a href="#cb153-14" aria-hidden="true" tabindex="-1"></a><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>
|
||
<span id="cb153-15"><a href="#cb153-15" aria-hidden="true" tabindex="-1"></a><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> ()</span></code></pre></div>
|
||
<p>Using these, we can rewrite our earlier examples:</p>
|
||
<div class="sourceCode" id="cb154"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb154-1"><a href="#cb154-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb154-2"><a href="#cb154-2" aria-hidden="true" tabindex="-1"></a>printList xs <span class="ot">=</span> <span class="fu">mapM_</span> <span class="fu">print</span> xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb155"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb155-1"><a href="#cb155-1" aria-hidden="true" tabindex="-1"></a>readAndSum n <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb155-2"><a href="#cb155-2" aria-hidden="true" tabindex="-1"></a> numbers <span class="ot"><-</span> replicateM n <span class="fu">readLn</span></span>
|
||
<span id="cb155-3"><a href="#cb155-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">sum</span> numbers)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb156"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb156-1"><a href="#cb156-1" aria-hidden="true" tabindex="-1"></a><span class="ot">ask ::</span> [<span class="dt">String</span>] <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb156-2"><a href="#cb156-2" aria-hidden="true" tabindex="-1"></a>ask questions <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb156-3"><a href="#cb156-3" aria-hidden="true" tabindex="-1"></a> forM questions askOne</span>
|
||
<span id="cb156-4"><a href="#cb156-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb156-5"><a href="#cb156-5" aria-hidden="true" tabindex="-1"></a><span class="ot">askOne ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb156-6"><a href="#cb156-6" aria-hidden="true" tabindex="-1"></a>askOne question <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb156-7"><a href="#cb156-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStr</span> question</span>
|
||
<span id="cb156-8"><a href="#cb156-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"?"</span></span>
|
||
<span id="cb156-9"><a href="#cb156-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">getLine</span></span></code></pre></div>
|
||
<h2 data-number="11.6" 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="cb157"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb157-1"><a href="#cb157-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is not OK, putStrLn is way too left</span></span>
|
||
<span id="cb157-2"><a href="#cb157-2" aria-hidden="true" tabindex="-1"></a>foo <span class="ot">=</span> <span class="kw">do</span> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb157-3"><a href="#cb157-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> y</span>
|
||
<span id="cb157-4"><a href="#cb157-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb157-5"><a href="#cb157-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is not OK either</span></span>
|
||
<span id="cb157-6"><a href="#cb157-6" aria-hidden="true" tabindex="-1"></a>foo <span class="ot">=</span> <span class="kw">do</span> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb157-7"><a href="#cb157-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> y</span>
|
||
<span id="cb157-8"><a href="#cb157-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb157-9"><a href="#cb157-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is OK</span></span>
|
||
<span id="cb157-10"><a href="#cb157-10" aria-hidden="true" tabindex="-1"></a>foo <span class="ot">=</span> <span class="kw">do</span> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb157-11"><a href="#cb157-11" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> y</span>
|
||
<span id="cb157-12"><a href="#cb157-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb157-13"><a href="#cb157-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is also OK: putting a line break after do</span></span>
|
||
<span id="cb157-14"><a href="#cb157-14" aria-hidden="true" tabindex="-1"></a>foo <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb157-15"><a href="#cb157-15" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb157-16"><a href="#cb157-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> y</span></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="cb158"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb158-1"><a href="#cb158-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is not OK, the string starts a new operation</span></span>
|
||
<span id="cb158-2"><a href="#cb158-2" aria-hidden="true" tabindex="-1"></a>quux <span class="ot">=</span> <span class="kw">do</span> <span class="fu">putStrLn</span></span>
|
||
<span id="cb158-3"><a href="#cb158-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"this long string"</span></span>
|
||
<span id="cb158-4"><a href="#cb158-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> <span class="dv">1</span></span>
|
||
<span id="cb158-5"><a href="#cb158-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb158-6"><a href="#cb158-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is OK</span></span>
|
||
<span id="cb158-7"><a href="#cb158-7" aria-hidden="true" tabindex="-1"></a>quux <span class="ot">=</span> <span class="kw">do</span> <span class="fu">putStrLn</span></span>
|
||
<span id="cb158-8"><a href="#cb158-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"this long string"</span></span>
|
||
<span id="cb158-9"><a href="#cb158-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>Here’s one more example, with nested do-blocks, and two different
|
||
valid indentations.</p>
|
||
<div class="sourceCode" id="cb159"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb159-1"><a href="#cb159-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is OK</span></span>
|
||
<span id="cb159-2"><a href="#cb159-2" aria-hidden="true" tabindex="-1"></a>foo x <span class="ot">=</span> <span class="kw">do</span> quux</span>
|
||
<span id="cb159-3"><a href="#cb159-3" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> blorg</span>
|
||
<span id="cb159-4"><a href="#cb159-4" aria-hidden="true" tabindex="-1"></a> when y (<span class="kw">do</span> thing</span>
|
||
<span id="cb159-5"><a href="#cb159-5" aria-hidden="true" tabindex="-1"></a> otherThing)</span>
|
||
<span id="cb159-6"><a href="#cb159-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> <span class="dv">3</span></span>
|
||
<span id="cb159-7"><a href="#cb159-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb159-8"><a href="#cb159-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is also OK: starting putting a line break after do, using $</span></span>
|
||
<span id="cb159-9"><a href="#cb159-9" aria-hidden="true" tabindex="-1"></a>foo x <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb159-10"><a href="#cb159-10" aria-hidden="true" tabindex="-1"></a> quux</span>
|
||
<span id="cb159-11"><a href="#cb159-11" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> blorg</span>
|
||
<span id="cb159-12"><a href="#cb159-12" aria-hidden="true" tabindex="-1"></a> when y <span class="op">$</span> <span class="kw">do</span></span>
|
||
<span id="cb159-13"><a href="#cb159-13" aria-hidden="true" tabindex="-1"></a> thing</span>
|
||
<span id="cb159-14"><a href="#cb159-14" aria-hidden="true" tabindex="-1"></a> otherThing</span>
|
||
<span id="cb159-15"><a href="#cb159-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> <span class="dv">3</span></span></code></pre></div>
|
||
<h2 data-number="11.7" 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="cb160"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb160-1"><a href="#cb160-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- split string into lines</span></span>
|
||
<span id="cb160-2"><a href="#cb160-2" aria-hidden="true" tabindex="-1"></a><span class="fu">lines</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</span>
|
||
<span id="cb160-3"><a href="#cb160-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- `isSuffixOf suf list` is true if list ends in suf</span></span>
|
||
<span id="cb160-4"><a href="#cb160-4" aria-hidden="true" tabindex="-1"></a>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></span>
|
||
<span id="cb160-5"><a href="#cb160-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- `isInfixOf inf list` is true if inf occurs inside list</span></span>
|
||
<span id="cb160-6"><a href="#cb160-6" aria-hidden="true" tabindex="-1"></a>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></span>
|
||
<span id="cb160-7"><a href="#cb160-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- FilePath is just an alias for String</span></span>
|
||
<span id="cb160-8"><a href="#cb160-8" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">FilePath</span> <span class="ot">=</span> <span class="dt">String</span></span>
|
||
<span id="cb160-9"><a href="#cb160-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- get entire contents of file</span></span>
|
||
<span id="cb160-10"><a href="#cb160-10" aria-hidden="true" tabindex="-1"></a><span class="fu">readFile</span><span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb160-11"><a href="#cb160-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- list files in directory</span></span>
|
||
<span id="cb160-12"><a href="#cb160-12" aria-hidden="true" tabindex="-1"></a>System.Directory.listDirectory<span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">FilePath</span>]</span>
|
||
<span id="cb160-13"><a href="#cb160-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- is the given file a directory?</span></span>
|
||
<span id="cb160-14"><a href="#cb160-14" aria-hidden="true" tabindex="-1"></a>System.Directory.doesDirectoryExist<span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></span></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/Examples/ReadTypes.hs"><code>exercises/Examples/ReadTypes.hs</code></a>.</p>
|
||
<div class="sourceCode" id="cb161"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb161-1"><a href="#cb161-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Examples.ReadTypes</span> <span class="kw">where</span></span>
|
||
<span id="cb161-2"><a href="#cb161-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-3"><a href="#cb161-3" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad</span> (forM)</span>
|
||
<span id="cb161-4"><a href="#cb161-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (isInfixOf, isSuffixOf)</span>
|
||
<span id="cb161-5"><a href="#cb161-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">System.Directory</span> (listDirectory, doesDirectoryExist)</span>
|
||
<span id="cb161-6"><a href="#cb161-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-7"><a href="#cb161-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- a line is a type signature if it contains :: but does not contain =</span></span>
|
||
<span id="cb161-8"><a href="#cb161-8" aria-hidden="true" tabindex="-1"></a><span class="ot">isTypeSignature ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb161-9"><a href="#cb161-9" aria-hidden="true" tabindex="-1"></a>isTypeSignature s <span class="ot">=</span> <span class="fu">not</span> (isInfixOf <span class="st">"="</span> s) <span class="op">&&</span> isInfixOf <span class="st">"::"</span> s</span>
|
||
<span id="cb161-10"><a href="#cb161-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-11"><a href="#cb161-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- return list of types for a .hs file</span></span>
|
||
<span id="cb161-12"><a href="#cb161-12" aria-hidden="true" tabindex="-1"></a><span class="ot">readTypesFile ::</span> <span class="dt">FilePath</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb161-13"><a href="#cb161-13" aria-hidden="true" tabindex="-1"></a>readTypesFile file</span>
|
||
<span id="cb161-14"><a href="#cb161-14" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> isSuffixOf <span class="st">".hs"</span> file <span class="ot">=</span> <span class="kw">do</span> content <span class="ot"><-</span> <span class="fu">readFile</span> file</span>
|
||
<span id="cb161-15"><a href="#cb161-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> ls <span class="ot">=</span> <span class="fu">lines</span> content</span>
|
||
<span id="cb161-16"><a href="#cb161-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">filter</span> isTypeSignature ls)</span>
|
||
<span id="cb161-17"><a href="#cb161-17" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">return</span> []</span>
|
||
<span id="cb161-18"><a href="#cb161-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-19"><a href="#cb161-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- list children of directory, prepend directory name</span></span>
|
||
<span id="cb161-20"><a href="#cb161-20" aria-hidden="true" tabindex="-1"></a><span class="ot">qualifiedChildren ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb161-21"><a href="#cb161-21" aria-hidden="true" tabindex="-1"></a>qualifiedChildren path <span class="ot">=</span> <span class="kw">do</span> childs <span class="ot"><-</span> listDirectory path</span>
|
||
<span id="cb161-22"><a href="#cb161-22" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">map</span> (\name <span class="ot">-></span> path<span class="op">++</span><span class="st">"/"</span><span class="op">++</span>name) childs)</span>
|
||
<span id="cb161-23"><a href="#cb161-23" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-24"><a href="#cb161-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- get type signatures for all entries in given directory</span></span>
|
||
<span id="cb161-25"><a href="#cb161-25" aria-hidden="true" tabindex="-1"></a><span class="co">-- note mutual recursion with readTypes</span></span>
|
||
<span id="cb161-26"><a href="#cb161-26" aria-hidden="true" tabindex="-1"></a><span class="ot">readTypesDir ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb161-27"><a href="#cb161-27" aria-hidden="true" tabindex="-1"></a>readTypesDir path <span class="ot">=</span> <span class="kw">do</span> childs <span class="ot"><-</span> qualifiedChildren path</span>
|
||
<span id="cb161-28"><a href="#cb161-28" aria-hidden="true" tabindex="-1"></a> typess <span class="ot"><-</span> forM childs readTypes</span>
|
||
<span id="cb161-29"><a href="#cb161-29" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">concat</span> typess)</span>
|
||
<span id="cb161-30"><a href="#cb161-30" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-31"><a href="#cb161-31" aria-hidden="true" tabindex="-1"></a><span class="co">-- recursively read types contained in a file or directory</span></span>
|
||
<span id="cb161-32"><a href="#cb161-32" aria-hidden="true" tabindex="-1"></a><span class="co">-- note mutual recursion with readTypesDir</span></span>
|
||
<span id="cb161-33"><a href="#cb161-33" aria-hidden="true" tabindex="-1"></a><span class="ot">readTypes ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb161-34"><a href="#cb161-34" aria-hidden="true" tabindex="-1"></a>readTypes path <span class="ot">=</span> <span class="kw">do</span> isDir <span class="ot"><-</span> doesDirectoryExist path</span>
|
||
<span id="cb161-35"><a href="#cb161-35" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> isDir <span class="kw">then</span> readTypesDir path <span class="kw">else</span> readTypesFile path</span>
|
||
<span id="cb161-36"><a href="#cb161-36" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb161-37"><a href="#cb161-37" aria-hidden="true" tabindex="-1"></a><span class="co">-- main is the IO action that gets run when you run the program</span></span>
|
||
<span id="cb161-38"><a href="#cb161-38" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb161-39"><a href="#cb161-39" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span> ts <span class="ot"><-</span> readTypes <span class="st">"."</span></span>
|
||
<span id="cb161-40"><a href="#cb161-40" aria-hidden="true" tabindex="-1"></a> <span class="fu">mapM_</span> <span class="fu">putStrLn</span> ts</span></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="cb162"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb162-1"><a href="#cb162-1" aria-hidden="true" tabindex="-1"></a><span class="op">$</span> stack runhaskell ReadTypes.hs</span>
|
||
<span id="cb162-2"><a href="#cb162-2" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb162-3"><a href="#cb162-3" aria-hidden="true" tabindex="-1"></a><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>)</span>
|
||
<span id="cb162-4"><a href="#cb162-4" aria-hidden="true" tabindex="-1"></a><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>)</span>
|
||
<span id="cb162-5"><a href="#cb162-5" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="fu">and</span> so on</span></code></pre></div>
|
||
<p>The exact output will vary according to the contents of the
|
||
directory, of course.</p>
|
||
<h2 data-number="11.8" 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="cb163"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb163-1"><a href="#cb163-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> x <span class="ot">=</span> <span class="fu">print</span> <span class="dv">1</span> <span class="co">-- creates operation, doesn't run it</span></span>
|
||
<span id="cb163-2"><a href="#cb163-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> x <span class="co">-- runs the operation</span></span>
|
||
<span id="cb163-3"><a href="#cb163-3" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb163-4"><a href="#cb163-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> x <span class="co">-- runs it again!</span></span>
|
||
<span id="cb163-5"><a href="#cb163-5" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span></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="cb164"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb164-1"><a href="#cb164-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb164-2"><a href="#cb164-2" aria-hidden="true" tabindex="-1"></a>choice a b <span class="ot">=</span></span>
|
||
<span id="cb164-3"><a href="#cb164-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">do</span> <span class="fu">putStr</span> <span class="st">"a or b? "</span></span>
|
||
<span id="cb164-4"><a href="#cb164-4" aria-hidden="true" tabindex="-1"></a> x <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb164-5"><a href="#cb164-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> x <span class="kw">of</span> <span class="st">"a"</span> <span class="ot">-></span> a</span>
|
||
<span id="cb164-6"><a href="#cb164-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"b"</span> <span class="ot">-></span> b</span>
|
||
<span id="cb164-7"><a href="#cb164-7" aria-hidden="true" tabindex="-1"></a> _ <span class="ot">-></span> <span class="kw">do</span> <span class="fu">putStrLn</span> <span class="st">"Wrong!"</span></span>
|
||
<span id="cb164-8"><a href="#cb164-8" aria-hidden="true" tabindex="-1"></a> choice a b</span></code></pre></div>
|
||
<div class="sourceCode" id="cb165"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb165-1"><a href="#cb165-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> choice (<span class="fu">putStrLn</span> <span class="st">"A!!!!"</span>) (<span class="fu">putStrLn</span> <span class="st">"B!!!!"</span>)</span>
|
||
<span id="cb165-2"><a href="#cb165-2" aria-hidden="true" tabindex="-1"></a>a <span class="fu">or</span> b<span class="op">?</span> z</span>
|
||
<span id="cb165-3"><a href="#cb165-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Wrong</span><span class="op">!</span></span>
|
||
<span id="cb165-4"><a href="#cb165-4" aria-hidden="true" tabindex="-1"></a>a <span class="fu">or</span> b<span class="op">?</span> a</span>
|
||
<span id="cb165-5"><a href="#cb165-5" aria-hidden="true" tabindex="-1"></a><span class="dt">A</span><span class="op">!!!!</span></span></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="cb166"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb166-1"><a href="#cb166-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span><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>
|
||
<span id="cb166-2"><a href="#cb166-2" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span> op [] <span class="ot">=</span> <span class="fu">return</span> () <span class="co">-- do nothing for an empty list</span></span>
|
||
<span id="cb166-3"><a href="#cb166-3" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span> op (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> op x <span class="co">-- run operation on first element</span></span>
|
||
<span id="cb166-4"><a href="#cb166-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">mapM_</span> op xs <span class="co">-- run operation on rest of list, recursively</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb167"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb167-1"><a href="#cb167-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">mapM_</span> <span class="fu">print</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb167-2"><a href="#cb167-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb167-3"><a href="#cb167-3" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
|
||
<span id="cb167-4"><a href="#cb167-4" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></code></pre></div>
|
||
<h2 data-number="11.9" 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="cb168"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb168-1"><a href="#cb168-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb168-2"><a href="#cb168-2" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb168-3"><a href="#cb168-3" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb168-4"><a href="#cb168-4" aria-hidden="true" tabindex="-1"></a><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></span></code></pre></div>
|
||
<p>Here are some examples of using an IORef in GHCi:</p>
|
||
<div class="sourceCode" id="cb169"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb169-1"><a href="#cb169-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>m <span class="op">+</span><span class="dt">Data.IORef</span></span>
|
||
<span id="cb169-2"><a href="#cb169-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> myRef <span class="ot"><-</span> newIORef <span class="st">"banana"</span></span>
|
||
<span id="cb169-3"><a href="#cb169-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> readIORef myRef</span>
|
||
<span id="cb169-4"><a href="#cb169-4" aria-hidden="true" tabindex="-1"></a><span class="st">"banana"</span></span>
|
||
<span id="cb169-5"><a href="#cb169-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> writeIORef myRef <span class="st">"apple"</span></span>
|
||
<span id="cb169-6"><a href="#cb169-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> readIORef myRef</span>
|
||
<span id="cb169-7"><a href="#cb169-7" aria-hidden="true" tabindex="-1"></a><span class="st">"apple"</span></span>
|
||
<span id="cb169-8"><a href="#cb169-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> modifyIORef myRef <span class="fu">reverse</span></span>
|
||
<span id="cb169-9"><a href="#cb169-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.IORef</span><span class="op">></span> readIORef myRef</span>
|
||
<span id="cb169-10"><a href="#cb169-10" aria-hidden="true" tabindex="-1"></a><span class="st">"elppa"</span></span></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="cb170"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb170-1"><a href="#cb170-1" aria-hidden="true" tabindex="-1"></a><span class="ot">sumList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Int</span></span>
|
||
<span id="cb170-2"><a href="#cb170-2" aria-hidden="true" tabindex="-1"></a>sumList xs <span class="ot">=</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></span>
|
||
<span id="cb170-3"><a href="#cb170-3" aria-hidden="true" tabindex="-1"></a> forM_ xs (\x <span class="ot">-></span> modifyIORef r (x<span class="op">+</span>)) <span class="co">-- for every xs, add it to r</span></span>
|
||
<span id="cb170-4"><a href="#cb170-4" aria-hidden="true" tabindex="-1"></a> readIORef r <span class="co">-- get last value of r</span></span></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 data-number="11.10" 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="cb171"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb171-1"><a href="#cb171-1" aria-hidden="true" tabindex="-1"></a><span class="ot">op ::</span> <span class="dt">X</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Y</span></span>
|
||
<span id="cb171-2"><a href="#cb171-2" aria-hidden="true" tabindex="-1"></a>op arg <span class="ot">=</span> <span class="kw">do</span> operation <span class="co">-- run operation</span></span>
|
||
<span id="cb171-3"><a href="#cb171-3" aria-hidden="true" tabindex="-1"></a> operation2 arg <span class="co">-- run operation with argument</span></span>
|
||
<span id="cb171-4"><a href="#cb171-4" aria-hidden="true" tabindex="-1"></a> result <span class="ot"><-</span> operation3 arg <span class="co">-- run operation with argument, store result</span></span>
|
||
<span id="cb171-5"><a href="#cb171-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> something <span class="ot">=</span> f result <span class="co">-- run a pure function f, store result</span></span>
|
||
<span id="cb171-6"><a href="#cb171-6" aria-hidden="true" tabindex="-1"></a> finalOperation <span class="co">-- last operation produces the the return value</span></span></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="cb172"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb172-1"><a href="#cb172-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- printing & reading</span></span>
|
||
<span id="cb172-2"><a href="#cb172-2" aria-hidden="true" tabindex="-1"></a><span class="fu">putStr</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb172-3"><a href="#cb172-3" aria-hidden="true" tabindex="-1"></a><span class="fu">putStrLn</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb172-4"><a href="#cb172-4" aria-hidden="true" tabindex="-1"></a><span class="fu">print</span><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>
|
||
<span id="cb172-5"><a href="#cb172-5" aria-hidden="true" tabindex="-1"></a><span class="fu">getLine</span><span class="ot"> ::</span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb172-6"><a href="#cb172-6" aria-hidden="true" tabindex="-1"></a><span class="fu">readLn</span><span class="ot"> ::</span> <span class="dt">Read</span> a <span class="ot">=></span> <span class="dt">IO</span> a</span>
|
||
<span id="cb172-7"><a href="#cb172-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb172-8"><a href="#cb172-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- control structures from Control.Monad</span></span>
|
||
<span id="cb172-9"><a href="#cb172-9" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb172-10"><a href="#cb172-10" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb172-11"><a href="#cb172-11" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb172-12"><a href="#cb172-12" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb172-13"><a href="#cb172-13" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span><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></span>
|
||
<span id="cb172-14"><a href="#cb172-14" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span><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></span>
|
||
<span id="cb172-15"><a href="#cb172-15" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb172-16"><a href="#cb172-16" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb172-17"><a href="#cb172-17" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb172-18"><a href="#cb172-18" aria-hidden="true" tabindex="-1"></a><span class="co">-- files</span></span>
|
||
<span id="cb172-19"><a href="#cb172-19" aria-hidden="true" tabindex="-1"></a><span class="fu">readFile</span><span class="ot"> ::</span> <span class="dt">FilePath</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span></code></pre></div>
|
||
<h2 data-number="11.11" 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="cb173"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb173-1"><a href="#cb173-1" aria-hidden="true" tabindex="-1"></a>foo x <span class="ot">=</span> <span class="kw">do</span> <span class="fu">putStrLn</span> x</span>
|
||
<span id="cb173-2"><a href="#cb173-2" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb173-3"><a href="#cb173-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">length</span> y)</span></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="cb174"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb174-1"><a href="#cb174-1" aria-hidden="true" tabindex="-1"></a><span class="ot">quux ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb174-2"><a href="#cb174-2" aria-hidden="true" tabindex="-1"></a>quux q <span class="ot">=</span> <span class="kw">do</span> y <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb174-3"><a href="#cb174-3" aria-hidden="true" tabindex="-1"></a> z <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb174-4"><a href="#cb174-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> (y<span class="op">++</span>z)</span>
|
||
<span id="cb174-5"><a href="#cb174-5" aria-hidden="true" tabindex="-1"></a> <span class="op">????</span></span></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? That is, what
|
||
values <code>x</code> does it call <code>print x</code> for. The value
|
||
produced by <code>blorg</code> doesn’t count.</p>
|
||
<div class="sourceCode" id="cb175"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb175-1"><a href="#cb175-1" aria-hidden="true" tabindex="-1"></a>blorg [] <span class="ot">=</span> <span class="fu">return</span> <span class="dv">0</span></span>
|
||
<span id="cb175-2"><a href="#cb175-2" aria-hidden="true" tabindex="-1"></a>blorg (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> m <span class="ot"><-</span> blorg xs</span>
|
||
<span id="cb175-3"><a href="#cb175-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> x</span>
|
||
<span id="cb175-4"><a href="#cb175-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (m<span class="op">+</span>x)</span></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 data-number="11.12" 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>
|
||
</ul>
|
||
<h1 data-number="12" id="lecture-12-fmap-fmap-fmap"><span
|
||
class="header-section-number">12</span> Lecture 12: fmap fmap fmap</h1>
|
||
<h2 data-number="12.1" id="contents-1"><span
|
||
class="header-section-number">12.1</span> Contents</h2>
|
||
<ul>
|
||
<li>Functors</li>
|
||
</ul>
|
||
<h2 data-number="12.2" id="functors"><span
|
||
class="header-section-number">12.2</span> Functors</h2>
|
||
<h3 data-number="12.2.1" 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="cb176"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb176-1"><a href="#cb176-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span><span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb176-2"><a href="#cb176-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb176-3"><a href="#cb176-3" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> g (x<span class="op">:</span>xs) <span class="ot">=</span> g x <span class="op">:</span> <span class="fu">map</span> g xs</span></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="cb177"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb177-1"><a href="#cb177-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="op">||</span> <span class="dt">True</span>) [<span class="dt">True</span>, <span class="dt">True</span>, <span class="dt">False</span>]</span>
|
||
<span id="cb177-2"><a href="#cb177-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dt">True</span> <span class="op">||</span> <span class="dt">True</span>, <span class="dt">True</span> <span class="op">||</span> <span class="dt">True</span>, <span class="dt">False</span> <span class="op">||</span> <span class="dt">True</span>]</span>
|
||
<span id="cb177-3"><a href="#cb177-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dt">True</span>, <span class="dt">True</span>, <span class="dt">True</span>]</span>
|
||
<span id="cb177-4"><a href="#cb177-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb177-5"><a href="#cb177-5" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="op">+</span><span class="dv">1</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb177-6"><a href="#cb177-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">1</span> <span class="op">+</span> <span class="dv">1</span>, <span class="dv">2</span> <span class="op">+</span> <span class="dv">1</span>, <span class="dv">3</span> <span class="op">+</span> <span class="dv">1</span>]</span>
|
||
<span id="cb177-7"><a href="#cb177-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">4</span>]</span>
|
||
<span id="cb177-8"><a href="#cb177-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb177-9"><a href="#cb177-9" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> (<span class="op">++</span><span class="st">"1"</span>) [<span class="st">"1"</span>, <span class="st">"2"</span>, <span class="st">"3"</span>]</span>
|
||
<span id="cb177-10"><a href="#cb177-10" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"1"</span> <span class="op">++</span> <span class="st">"1"</span>, <span class="st">"2"</span> <span class="op">++</span> <span class="st">"1"</span>, <span class="st">"3"</span> <span class="op">++</span> <span class="st">"1"</span>]</span>
|
||
<span id="cb177-11"><a href="#cb177-11" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"11"</span>, <span class="st">"21"</span>, <span class="st">"31"</span>]</span></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 g to a list" />
|
||
<figcaption aria-hidden="true">Mapping a function <code>g</code> 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="cb178"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb178-1"><a href="#cb178-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb178-2"><a href="#cb178-2" aria-hidden="true" tabindex="-1"></a>mapMaybe f <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb178-3"><a href="#cb178-3" aria-hidden="true" tabindex="-1"></a>mapMaybe f (<span class="dt">Just</span> x) <span class="ot">=</span> <span class="dt">Just</span> (f x)</span></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="cb179"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb179-1"><a href="#cb179-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Leaf</span> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</span>
|
||
<span id="cb179-2"><a href="#cb179-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb179-3"><a href="#cb179-3" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb179-4"><a href="#cb179-4" aria-hidden="true" tabindex="-1"></a>mapTree f <span class="dt">Leaf</span> <span class="ot">=</span> <span class="dt">Leaf</span></span>
|
||
<span id="cb179-5"><a href="#cb179-5" aria-hidden="true" tabindex="-1"></a>mapTree f (<span class="dt">Node</span> val left right) <span class="ot">=</span> <span class="dt">Node</span> (f val) (mapTree f left) (mapTree f right)</span></code></pre></div>
|
||
<p>A binary tree might look like this:</p>
|
||
<figure>
|
||
<img src="img/mapTreeBefore.svg" alt="A binary tree" />
|
||
<figcaption aria-hidden="true">A binary tree</figcaption>
|
||
</figure>
|
||
<p>After <code>mapTree g</code> the tree would looke like this:</p>
|
||
<figure>
|
||
<img src="img/mapTreeAfter.svg"
|
||
alt="A binary tree after mapping g into its nodes" />
|
||
<figcaption aria-hidden="true">A binary tree after mapping
|
||
<code>g</code> into its nodes</figcaption>
|
||
</figure>
|
||
<h3 data-number="12.2.2" 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="cb180"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb180-1"><a href="#cb180-1" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span><span class="ot"> ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb180-2"><a href="#cb180-2" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb180-3"><a href="#cb180-3" aria-hidden="true" tabindex="-1"></a><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</span></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>, it seems we can’t 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="cb181"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb181-1"><a href="#cb181-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Mappable</span> m <span class="kw">where</span></span>
|
||
<span id="cb181-2"><a href="#cb181-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> mapThing ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> m <span class="ot">-></span> m</span>
|
||
<span id="cb181-3"><a href="#cb181-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb181-4"><a href="#cb181-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Mappable</span> (<span class="dt">Maybe</span> c) <span class="kw">where</span></span>
|
||
<span id="cb181-5"><a href="#cb181-5" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb181-6"><a href="#cb181-6" aria-hidden="true" tabindex="-1"></a> mapThing <span class="ot">=</span> <span class="op">...</span></span></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="cb182"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb182-1"><a href="#cb182-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="kw">where</span></span>
|
||
<span id="cb182-2"><a href="#cb182-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> fmap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</span></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="cb183"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb183-1"><a href="#cb183-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
|
||
<span id="cb183-2"><a href="#cb183-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- In this instance, the type of fmap is:</span></span>
|
||
<span id="cb183-3"><a href="#cb183-3" aria-hidden="true" tabindex="-1"></a> <span class="co">-- fmap :: (a -> b) -> Maybe a -> Maybe b</span></span>
|
||
<span id="cb183-4"><a href="#cb183-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb183-5"><a href="#cb183-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f (<span class="dt">Just</span> x) <span class="ot">=</span> <span class="dt">Just</span> (f x)</span></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="cb184"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb184-1"><a href="#cb184-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> [] <span class="kw">where</span></span>
|
||
<span id="cb184-2"><a href="#cb184-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> <span class="ot">=</span> <span class="fu">map</span></span></code></pre></div>
|
||
<p>Here’s the final of our examples, as a <code>Functor</code>
|
||
instance.</p>
|
||
<div class="sourceCode" id="cb185"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb185-1"><a href="#cb185-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Leaf</span> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a)</span>
|
||
<span id="cb185-2"><a href="#cb185-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb185-3"><a href="#cb185-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Tree</span> <span class="kw">where</span></span>
|
||
<span id="cb185-4"><a href="#cb185-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> _ <span class="dt">Leaf</span> <span class="ot">=</span> <span class="dt">Leaf</span></span>
|
||
<span id="cb185-5"><a href="#cb185-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f (<span class="dt">Node</span> val left right) <span class="ot">=</span> <span class="dt">Node</span> (f val) (<span class="fu">fmap</span> f left) (<span class="fu">fmap</span> f right)</span></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. As you progress in learning Haskell, you might get
|
||
interested in category theory, and it can be a valuable source of new
|
||
ideas for programming. Category theory can feel intimidating, so it’s
|
||
good to know that you can get on fine without it. For now, 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="cb186"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb186-1"><a href="#cb186-1" aria-hidden="true" tabindex="-1"></a>(<span class="op">+</span><span class="dv">1</span>) <span class="op"><$></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb186-2"><a href="#cb186-2" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="op"><$></span> <span class="dt">Just</span> <span class="dt">False</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">True</span></span>
|
||
<span id="cb186-3"><a href="#cb186-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb186-4"><a href="#cb186-4" aria-hidden="true" tabindex="-1"></a><span class="fu">reverse</span> <span class="op">.</span> <span class="fu">tail</span> <span class="op">$</span> <span class="st">"hello"</span> <span class="op">==></span> <span class="st">"olle"</span></span>
|
||
<span id="cb186-5"><a href="#cb186-5" aria-hidden="true" tabindex="-1"></a><span class="fu">reverse</span> <span class="op">.</span> <span class="fu">tail</span> <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"hello"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="st">"olle"</span></span>
|
||
<span id="cb186-6"><a href="#cb186-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- which is the same as</span></span>
|
||
<span id="cb186-7"><a href="#cb186-7" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> (<span class="fu">reverse</span> <span class="op">.</span> <span class="fu">tail</span>) (<span class="dt">Just</span> <span class="st">"hello"</span>) <span class="op">==></span> <span class="dt">Just</span> <span class="st">"olle"</span></span></code></pre></div>
|
||
<h2 data-number="12.3" 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="cb187"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb187-1"><a href="#cb187-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> <span class="fu">id</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="fu">map</span> <span class="fu">id</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb187-2"><a href="#cb187-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">map</span> <span class="fu">id</span> (<span class="dv">1</span><span class="op">:</span>[<span class="dv">2</span>,<span class="dv">3</span>])</span>
|
||
<span id="cb187-3"><a href="#cb187-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">id</span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">id</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb187-4"><a href="#cb187-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">id</span> [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb187-5"><a href="#cb187-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">id</span> <span class="dv">2</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">id</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb187-6"><a href="#cb187-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="dv">2</span> <span class="op">:</span> <span class="fu">id</span> <span class="dv">3</span> <span class="op">:</span> <span class="fu">map</span> <span class="fu">id</span> []</span>
|
||
<span id="cb187-7"><a href="#cb187-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="dv">2</span> <span class="op">:</span> <span class="dv">3</span> <span class="op">:</span> []</span>
|
||
<span id="cb187-8"><a href="#cb187-8" aria-hidden="true" tabindex="-1"></a> <span class="op">===</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p>On the other hand,</p>
|
||
<div class="sourceCode" id="cb188"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb188-1"><a href="#cb188-1" aria-hidden="true" tabindex="-1"></a><span class="fu">id</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span></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 if we apply <code>fmap</code> to a
|
||
function that changes nothing (<code>id</code>) the resulting function
|
||
(<code>fmap id</code>) again changes nothing. Thus, the act of applying
|
||
<code>fmap</code> itself preserves the structure of the functor.</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="cb189"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb189-1"><a href="#cb189-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb189-2"><a href="#cb189-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) <span class="dv">1</span> <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb189-3"><a href="#cb189-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">negate</span> (<span class="dv">1</span> <span class="op">*</span> <span class="dv">2</span>) <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb189-4"><a href="#cb189-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="op">-</span><span class="dv">2</span> <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb189-5"><a href="#cb189-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="op">-</span><span class="dv">2</span> <span class="op">:</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) <span class="dv">2</span> <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">3</span>]</span>
|
||
<span id="cb189-6"><a href="#cb189-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="op">-</span><span class="dv">2</span> <span class="op">:</span> <span class="op">-</span><span class="dv">4</span> <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">3</span>]</span>
|
||
<span id="cb189-7"><a href="#cb189-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="op">-</span><span class="dv">2</span> <span class="op">:</span> <span class="op">-</span><span class="dv">4</span> <span class="op">:</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) <span class="dv">3</span> <span class="op">:</span> <span class="fu">map</span> (<span class="fu">negate</span><span class="op">.</span>(<span class="op">*</span><span class="dv">2</span>)) []</span>
|
||
<span id="cb189-8"><a href="#cb189-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="op">-</span><span class="dv">2</span> <span class="op">:</span> <span class="op">-</span><span class="dv">4</span> <span class="op">:</span> <span class="op">-</span><span class="dv">6</span> <span class="op">:</span> []</span>
|
||
<span id="cb189-9"><a href="#cb189-9" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="op">-</span><span class="dv">2</span>,<span class="op">-</span><span class="dv">4</span>,<span class="op">-</span><span class="dv">6</span>]</span></code></pre></div>
|
||
<p>Let’s consider the right-hand side of the second functor law in this
|
||
case:</p>
|
||
<div class="sourceCode" id="cb190"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb190-1"><a href="#cb190-1" aria-hidden="true" tabindex="-1"></a>(<span class="fu">fmap</span> <span class="fu">negate</span> <span class="op">.</span> <span class="fu">fmap</span> (<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> (<span class="fu">map</span> <span class="fu">negate</span> <span class="op">.</span> <span class="fu">map</span> (<span class="op">*</span><span class="dv">2</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb190-2"><a href="#cb190-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">map</span> <span class="fu">negate</span> (<span class="fu">map</span> (<span class="op">*</span><span class="dv">2</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])</span>
|
||
<span id="cb190-3"><a href="#cb190-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">map</span> <span class="fu">negate</span> [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span>
|
||
<span id="cb190-4"><a href="#cb190-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="op">-</span><span class="dv">2</span>,<span class="op">-</span><span class="dv">4</span>,<span class="op">-</span><span class="dv">6</span>]</span></code></pre></div>
|
||
<p>The second functor law turns out to hold in this particular case. In
|
||
fact, it holds in all cases (exercise!).</p>
|
||
<p>In general, the second functor law says that composing two functions
|
||
first and then applying <code>fmap</code> must yield the same result as
|
||
performing <code>fmap</code> on those functions and then composing the
|
||
resulting function. In other words, the order of applying
|
||
<code>fmap</code> and composing doesn’t matter. (These two operations
|
||
are said to <em>commute</em>.)</p>
|
||
<!-- I don't know if this is helpful or more confusing:
|
||
You might remember the distributivity law from algebra:
|
||
```
|
||
x * (y + z) === x * y + x * z
|
||
```
|
||
If you squint your eyes very hard, you might see that in the case of functors
|
||
`.` is kind of like `+` above and `fmap f` is kind of like the section `(x *)`.
|
||
In a very abstract sense, the property of preserving the second functor law is
|
||
analogous to distributivity. The key point is that we can swap the order in
|
||
which we perform `fmap` and `.` and expect to get the same result. Purity is
|
||
necessary for having a concept like functor laws in a programming language so
|
||
this topic connects to equational reasoning discussed in chapter 10.
|
||
-->
|
||
<p>There are also higher-order functions that fail to satisfy functor
|
||
laws. Consider the function <code>badMap</code>:</p>
|
||
<div class="sourceCode" id="cb191"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb191-1"><a href="#cb191-1" aria-hidden="true" tabindex="-1"></a><span class="ot">badMap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> [a] <span class="ot">-></span> [b]</span>
|
||
<span id="cb191-2"><a href="#cb191-2" aria-hidden="true" tabindex="-1"></a>badMap f [] <span class="ot">=</span> []</span>
|
||
<span id="cb191-3"><a href="#cb191-3" aria-hidden="true" tabindex="-1"></a>badMap f (x<span class="op">:</span>y<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> badMap f xs</span>
|
||
<span id="cb191-4"><a href="#cb191-4" aria-hidden="true" tabindex="-1"></a>badMap f (x<span class="op">:</span>xs) <span class="ot">=</span> f x <span class="op">:</span> badMap f xs</span></code></pre></div>
|
||
<p>This function violates the first functor law. For instance:</p>
|
||
<div class="sourceCode" id="cb192"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb192-1"><a href="#cb192-1" aria-hidden="true" tabindex="-1"></a>badMap <span class="fu">id</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> badMap <span class="fu">id</span> (<span class="dv">1</span><span class="op">:</span><span class="dv">2</span><span class="op">:</span>[<span class="dv">3</span>])</span>
|
||
<span id="cb192-2"><a href="#cb192-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">id</span> <span class="dv">1</span> <span class="op">:</span> badMap <span class="fu">id</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb192-3"><a href="#cb192-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> badMap <span class="fu">id</span> [<span class="dv">3</span>]</span>
|
||
<span id="cb192-4"><a href="#cb192-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> badMap <span class="fu">id</span> (<span class="dv">3</span><span class="op">:</span>[])</span>
|
||
<span id="cb192-5"><a href="#cb192-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="fu">id</span> <span class="dv">3</span> <span class="op">:</span> badMap <span class="fu">id</span> []</span>
|
||
<span id="cb192-6"><a href="#cb192-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">:</span> <span class="dv">3</span> <span class="op">:</span> []</span>
|
||
<span id="cb192-7"><a href="#cb192-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">1</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p>Applying <code>badMap id</code> to the list <code>[1,2,3]</code>
|
||
changed the list as the element <code>2</code> was dropped.</p>
|
||
<p>As mentioned, Haskell compilers can’t detect if a functor obeys its
|
||
laws or not. A Haskell compiler would happily accept an instance
|
||
<code>Functor []</code> that used <code>badMap</code> instead of
|
||
<code>map</code> as the <code>fmap</code> implementation. This is a
|
||
limitation of the type system of Haskell. There are technologies such as
|
||
LiquidHaskell or dependently typed languages such as Agda, Idris, Coq,
|
||
or Lean that could actually enforce functor laws so that unlawful
|
||
functor instances wouldn’t compile. These technologies are outside the
|
||
scope of this course, however.</p>
|
||
<h2 data-number="12.4" 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"><span id="cb193-1"><a href="#cb193-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Int</span> <span class="kw">where</span></span>
|
||
<span id="cb193-2"><a href="#cb193-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb193-3"><a href="#cb193-3" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">1</span><span class="op">:</span><span class="dv">18</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb193-4"><a href="#cb193-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Expected</span> kind ‘<span class="op">*</span> <span class="ot">-></span> <span class="op">*</span>’, but ‘<span class="dt">Int</span>’ has kind ‘<span class="op">*</span>’</span>
|
||
<span id="cb193-5"><a href="#cb193-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘<span class="dt">Functor</span>’, namely ‘<span class="dt">Int</span>’</span>
|
||
<span id="cb193-6"><a href="#cb193-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the <span class="kw">instance</span> declaration for ‘<span class="dt">Functor</span> <span class="dt">Int</span>’</span></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"><span id="cb194-1"><a href="#cb194-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">Int</span></span>
|
||
<span id="cb194-2"><a href="#cb194-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Int</span><span class="ot"> ::</span> <span class="op">*</span></span>
|
||
<span id="cb194-3"><a href="#cb194-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">Maybe</span></span>
|
||
<span id="cb194-4"><a href="#cb194-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Maybe</span><span class="ot"> ::</span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span></span>
|
||
<span id="cb194-5"><a href="#cb194-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb194-6"><a href="#cb194-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Maybe</span> <span class="dt">Int</span><span class="ot"> ::</span> <span class="op">*</span></span></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"><span id="cb195-1"><a href="#cb195-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>info <span class="dt">Functor</span></span>
|
||
<span id="cb195-2"><a href="#cb195-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Functor</span> (<span class="ot">f ::</span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span>) <span class="kw">where</span></span>
|
||
<span id="cb195-3"><a href="#cb195-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> fmap ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</span>
|
||
<span id="cb195-4"><a href="#cb195-4" aria-hidden="true" tabindex="-1"></a><span class="op">...</span></span></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"><span id="cb196-1"><a href="#cb196-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- multiple type parameters</span></span>
|
||
<span id="cb196-2"><a href="#cb196-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">Either</span></span>
|
||
<span id="cb196-3"><a href="#cb196-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Either</span><span class="ot"> ::</span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span></span>
|
||
<span id="cb196-4"><a href="#cb196-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">data</span> <span class="dt">Either3</span> a b c <span class="ot">=</span> <span class="dt">Left</span> a <span class="op">|</span> <span class="dt">Middle</span> b <span class="op">|</span> <span class="dt">Right</span> c</span>
|
||
<span id="cb196-5"><a href="#cb196-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">Either3</span></span>
|
||
<span id="cb196-6"><a href="#cb196-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Either3</span><span class="ot"> ::</span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span> <span class="ot">-></span> <span class="op">*</span></span>
|
||
<span id="cb196-7"><a href="#cb196-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- a type parameter of kind *->*</span></span>
|
||
<span id="cb196-8"><a href="#cb196-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">data</span> <span class="dt">IntInside</span> f <span class="ot">=</span> <span class="dt">IntInside</span> (f <span class="dt">Int</span>)</span>
|
||
<span id="cb196-9"><a href="#cb196-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>kind <span class="dt">IntInside</span></span>
|
||
<span id="cb196-10"><a href="#cb196-10" aria-hidden="true" tabindex="-1"></a><span class="dt">IntInside</span><span class="ot"> ::</span> (<span class="op">*</span> <span class="ot">-></span> <span class="op">*</span>) <span class="ot">-></span> <span class="op">*</span></span></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 data-number="12.5" 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"><span id="cb197-1"><a href="#cb197-1" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span><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></span>
|
||
<span id="cb197-2"><a href="#cb197-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sum</span><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</span>
|
||
<span id="cb197-3"><a href="#cb197-3" aria-hidden="true" tabindex="-1"></a><span class="fu">minimum</span><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</span>
|
||
<span id="cb197-4"><a href="#cb197-4" aria-hidden="true" tabindex="-1"></a><span class="fu">foldMap</span><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</span></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"><span id="cb198-1"><a href="#cb198-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Foldable</span> (<span class="ot">t ::</span> <span class="op">*->*</span>) <span class="kw">where</span></span>
|
||
<span id="cb198-2"><a href="#cb198-2" aria-hidden="true" tabindex="-1"></a><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</span></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"><span id="cb199-1"><a href="#cb199-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Pair</span> a <span class="ot">=</span> <span class="dt">Pair</span> a a</span>
|
||
<span id="cb199-2"><a href="#cb199-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb199-3"><a href="#cb199-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb199-4"><a href="#cb199-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Pair</span> <span class="kw">where</span></span>
|
||
<span id="cb199-5"><a href="#cb199-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- fmap f applies f to all values</span></span>
|
||
<span id="cb199-6"><a href="#cb199-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f (<span class="dt">Pair</span> x y) <span class="ot">=</span> <span class="dt">Pair</span> (f x) (f y)</span>
|
||
<span id="cb199-7"><a href="#cb199-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb199-8"><a href="#cb199-8" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foldable</span> <span class="dt">Pair</span> <span class="kw">where</span></span>
|
||
<span id="cb199-9"><a href="#cb199-9" aria-hidden="true" tabindex="-1"></a> <span class="co">-- just like applying foldr over a list of length 2</span></span>
|
||
<span id="cb199-10"><a href="#cb199-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">foldr</span> f initialValue (<span class="dt">Pair</span> x y) <span class="ot">=</span> f x (f y initialValue)</span>
|
||
<span id="cb199-11"><a href="#cb199-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb199-12"><a href="#cb199-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- an example function that uses both instances</span></span>
|
||
<span id="cb199-13"><a href="#cb199-13" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb199-14"><a href="#cb199-14" aria-hidden="true" tabindex="-1"></a>doubleAndCount <span class="ot">=</span> <span class="fu">sum</span> <span class="op">.</span> <span class="fu">fmap</span> (<span class="op">*</span><span class="dv">2</span>)</span></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"><span id="cb200-1"><a href="#cb200-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> (<span class="op">+</span><span class="dv">1</span>) (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="op">==></span> <span class="dt">Pair</span> <span class="dv">4</span> <span class="dv">7</span></span>
|
||
<span id="cb200-2"><a href="#cb200-2" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> (<span class="op">+</span><span class="dv">1</span>) [<span class="dv">3</span>,<span class="dv">6</span>] <span class="op">==></span> [<span class="dv">4</span>,<span class="dv">7</span>]</span>
|
||
<span id="cb200-3"><a href="#cb200-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb200-4"><a href="#cb200-4" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">*</span>) <span class="dv">1</span> (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="op">==></span> <span class="dv">18</span></span>
|
||
<span id="cb200-5"><a href="#cb200-5" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">*</span>) <span class="dv">1</span> [<span class="dv">3</span>,<span class="dv">6</span>] <span class="op">==></span> <span class="dv">18</span></span>
|
||
<span id="cb200-6"><a href="#cb200-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb200-7"><a href="#cb200-7" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="op">==></span> <span class="dv">2</span></span>
|
||
<span id="cb200-8"><a href="#cb200-8" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> [<span class="dv">3</span>,<span class="dv">6</span>] <span class="op">==></span> <span class="dv">2</span></span>
|
||
<span id="cb200-9"><a href="#cb200-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb200-10"><a href="#cb200-10" aria-hidden="true" tabindex="-1"></a><span class="fu">minimum</span> (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb200-11"><a href="#cb200-11" aria-hidden="true" tabindex="-1"></a><span class="fu">minimum</span> [<span class="dv">3</span>,<span class="dv">6</span>] <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb200-12"><a href="#cb200-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb200-13"><a href="#cb200-13" aria-hidden="true" tabindex="-1"></a>doubleAndCount (<span class="dt">Pair</span> <span class="dv">3</span> <span class="dv">6</span>) <span class="op">==></span> <span class="dv">18</span></span>
|
||
<span id="cb200-14"><a href="#cb200-14" aria-hidden="true" tabindex="-1"></a>doubleAndCount [<span class="dv">3</span>,<span class="dv">6</span>] <span class="op">==></span> <span class="dv">18</span></span></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 data-number="12.6" 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 data-number="12.7" 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"><span id="cb201-1"><a href="#cb201-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Container</span> x <span class="ot">=</span> <span class="dt">Things</span> x [x]</span>
|
||
<span id="cb201-2"><a href="#cb201-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb201-3"><a href="#cb201-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Container</span> <span class="kw">where</span></span>
|
||
<span id="cb201-4"><a href="#cb201-4" aria-hidden="true" tabindex="-1"></a> <span class="op">????</span></span></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"><span id="cb202-1"><a href="#cb202-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Foo</span> x <span class="ot">=</span> <span class="dt">FooConst</span></span></code></pre></div>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>*</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>* -> *</code>
|
||
</li>
|
||
<li>
|
||
<code>Foo</code>
|
||
</li>
|
||
</ol>
|
||
<p>What’s the kind of <code>Bar</code>?</p>
|
||
<div class="sourceCode" id="cb203"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb203-1"><a href="#cb203-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Bar</span> <span class="ot">=</span> <span class="dt">Baz</span> <span class="op">|</span> <span class="dt">Qux</span> <span class="dt">Int</span></span></code></pre></div>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>*</code>
|
||
</li>
|
||
<li>
|
||
<code>* -> *</code>
|
||
</li>
|
||
<li>
|
||
<code>Bar</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="cb204"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb204-1"><a href="#cb204-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Container</span> x <span class="ot">=</span> <span class="dt">Things</span> x [x]</span>
|
||
<span id="cb204-2"><a href="#cb204-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb204-3"><a href="#cb204-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Foldable</span> <span class="dt">Container</span> <span class="kw">where</span></span>
|
||
<span id="cb204-4"><a href="#cb204-4" aria-hidden="true" tabindex="-1"></a> <span class="op">????</span></span></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 data-number="12.8" 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>
|
||
</ul>
|
||
<h1 data-number="13"
|
||
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. Category theory can be a rewarding topic for
|
||
a functional programmer, but it’s not a mandatory one.</p>
|
||
<h2 data-number="13.1" 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>: It’s not fun to
|
||
write.</p>
|
||
<div class="sourceCode" id="cb205"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb205-1"><a href="#cb205-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Try to login with a password.</span></span>
|
||
<span id="cb205-2"><a href="#cb205-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- `Just username` on success, `Nothing` otherwise.</span></span>
|
||
<span id="cb205-3"><a href="#cb205-3" aria-hidden="true" tabindex="-1"></a><span class="ot">login ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb205-4"><a href="#cb205-4" aria-hidden="true" tabindex="-1"></a>login <span class="st">"f4bulous!"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="st">"unicorn73"</span></span>
|
||
<span id="cb205-5"><a href="#cb205-5" aria-hidden="true" tabindex="-1"></a>login <span class="st">"swordfish"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="st">"megahacker"</span></span>
|
||
<span id="cb205-6"><a href="#cb205-6" aria-hidden="true" tabindex="-1"></a>login _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb205-7"><a href="#cb205-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb205-8"><a href="#cb205-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get a secret associated with a user.</span></span>
|
||
<span id="cb205-9"><a href="#cb205-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Not all users have secrets.</span></span>
|
||
<span id="cb205-10"><a href="#cb205-10" aria-hidden="true" tabindex="-1"></a><span class="ot">secret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb205-11"><a href="#cb205-11" aria-hidden="true" tabindex="-1"></a>secret <span class="st">"megahacker"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="st">"I like roses"</span></span>
|
||
<span id="cb205-12"><a href="#cb205-12" aria-hidden="true" tabindex="-1"></a>secret _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb205-13"><a href="#cb205-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb205-14"><a href="#cb205-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- Login and return the user's secret, if any</span></span>
|
||
<span id="cb205-15"><a href="#cb205-15" aria-hidden="true" tabindex="-1"></a><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb205-16"><a href="#cb205-16" aria-hidden="true" tabindex="-1"></a>stealSecret password <span class="ot">=</span></span>
|
||
<span id="cb205-17"><a href="#cb205-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> login password <span class="kw">of</span></span>
|
||
<span id="cb205-18"><a href="#cb205-18" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb205-19"><a href="#cb205-19" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> user <span class="ot">-></span> <span class="kw">case</span> secret user <span class="kw">of</span></span>
|
||
<span id="cb205-20"><a href="#cb205-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb205-21"><a href="#cb205-21" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> s <span class="ot">-></span> <span class="dt">Just</span> (<span class="st">"Stole secret: "</span><span class="op">++</span>s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb206"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb206-1"><a href="#cb206-1" aria-hidden="true" tabindex="-1"></a>stealSecret <span class="st">"swordfish"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="st">"Stole secret: I like roses"</span></span>
|
||
<span id="cb206-2"><a href="#cb206-2" aria-hidden="true" tabindex="-1"></a>stealSecret <span class="st">"f4bulous!"</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb206-3"><a href="#cb206-3" aria-hidden="true" tabindex="-1"></a>stealSecret <span class="st">"wrong_password"</span> <span class="op">==></span> <span class="dt">Nothing</span></span></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="cb207"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb207-1"><a href="#cb207-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get the value corresponding to a key from a key-value list.</span></span>
|
||
<span id="cb207-2"><a href="#cb207-2" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span><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</span></code></pre></div>
|
||
<div class="sourceCode" id="cb208"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb208-1"><a href="#cb208-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Set the value of key to val in the given key-value list,</span></span>
|
||
<span id="cb208-2"><a href="#cb208-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- but only if val is larger than the current value!</span></span>
|
||
<span id="cb208-3"><a href="#cb208-3" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb208-4"><a href="#cb208-4" aria-hidden="true" tabindex="-1"></a>increase key val assocs <span class="ot">=</span></span>
|
||
<span id="cb208-5"><a href="#cb208-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> <span class="fu">lookup</span> key assocs</span>
|
||
<span id="cb208-6"><a href="#cb208-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">of</span> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb208-7"><a href="#cb208-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> x <span class="ot">-></span> <span class="kw">if</span> (val <span class="op"><</span> x)</span>
|
||
<span id="cb208-8"><a href="#cb208-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb208-9"><a href="#cb208-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="dt">Just</span> ((key,val) <span class="op">:</span> delete (key,x) assocs)</span></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="cb209"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb209-1"><a href="#cb209-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb209-2"><a href="#cb209-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- if we failed, don't even bother running the next step:</span></span>
|
||
<span id="cb209-3"><a href="#cb209-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span> <span class="op">?></span> _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb209-4"><a href="#cb209-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- otherwise run the next step:</span></span>
|
||
<span id="cb209-5"><a href="#cb209-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> x <span class="op">?></span> f <span class="ot">=</span> f x</span></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="cb210"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb210-1"><a href="#cb210-1" aria-hidden="true" tabindex="-1"></a><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb210-2"><a href="#cb210-2" aria-hidden="true" tabindex="-1"></a>stealSecret password <span class="ot">=</span></span>
|
||
<span id="cb210-3"><a href="#cb210-3" aria-hidden="true" tabindex="-1"></a> login password <span class="op">?></span></span>
|
||
<span id="cb210-4"><a href="#cb210-4" aria-hidden="true" tabindex="-1"></a> secret <span class="op">?></span></span>
|
||
<span id="cb210-5"><a href="#cb210-5" aria-hidden="true" tabindex="-1"></a> decorate</span>
|
||
<span id="cb210-6"><a href="#cb210-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> decorate s <span class="ot">=</span> <span class="dt">Just</span> (<span class="st">"Stole secret: "</span><span class="op">++</span>s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb211"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb211-1"><a href="#cb211-1" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb211-2"><a href="#cb211-2" aria-hidden="true" tabindex="-1"></a>increase key val assocs <span class="ot">=</span></span>
|
||
<span id="cb211-3"><a href="#cb211-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">lookup</span> key assocs <span class="op">?></span></span>
|
||
<span id="cb211-4"><a href="#cb211-4" aria-hidden="true" tabindex="-1"></a> check <span class="op">?></span></span>
|
||
<span id="cb211-5"><a href="#cb211-5" aria-hidden="true" tabindex="-1"></a> buildResult</span>
|
||
<span id="cb211-6"><a href="#cb211-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> check x</span>
|
||
<span id="cb211-7"><a href="#cb211-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> val <span class="op"><</span> x <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb211-8"><a href="#cb211-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb211-9"><a href="#cb211-9" aria-hidden="true" tabindex="-1"></a> buildResult x <span class="ot">=</span> <span class="dt">Just</span> ((key,val) <span class="op">:</span> delete (key,x) assocs)</span></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="cb212"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb212-1"><a href="#cb212-1" aria-hidden="true" tabindex="-1"></a><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb212-2"><a href="#cb212-2" aria-hidden="true" tabindex="-1"></a>safeHead [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb212-3"><a href="#cb212-3" aria-hidden="true" tabindex="-1"></a>safeHead (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb212-4"><a href="#cb212-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb212-5"><a href="#cb212-5" aria-hidden="true" tabindex="-1"></a><span class="ot">safeTail ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</span>
|
||
<span id="cb212-6"><a href="#cb212-6" aria-hidden="true" tabindex="-1"></a>safeTail [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb212-7"><a href="#cb212-7" aria-hidden="true" tabindex="-1"></a>safeTail (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> xs</span>
|
||
<span id="cb212-8"><a href="#cb212-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb212-9"><a href="#cb212-9" aria-hidden="true" tabindex="-1"></a><span class="ot">safeThird ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb212-10"><a href="#cb212-10" aria-hidden="true" tabindex="-1"></a>safeThird xs <span class="ot">=</span> safeTail xs <span class="op">?></span> safeTail <span class="op">?></span> safeHead</span>
|
||
<span id="cb212-11"><a href="#cb212-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb212-12"><a href="#cb212-12" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb212-13"><a href="#cb212-13" aria-hidden="true" tabindex="-1"></a>safeNth <span class="dv">0</span> xs <span class="ot">=</span> safeHead xs</span>
|
||
<span id="cb212-14"><a href="#cb212-14" aria-hidden="true" tabindex="-1"></a>safeNth n xs <span class="ot">=</span> safeTail xs <span class="op">?></span> safeNth (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb213"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb213-1"><a href="#cb213-1" aria-hidden="true" tabindex="-1"></a>safeThird [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb213-2"><a href="#cb213-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">3</span></span>
|
||
<span id="cb213-3"><a href="#cb213-3" aria-hidden="true" tabindex="-1"></a>safeThird [<span class="dv">1</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb213-4"><a href="#cb213-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb213-5"><a href="#cb213-5" aria-hidden="true" tabindex="-1"></a>safeNth <span class="dv">5</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</span>
|
||
<span id="cb213-6"><a href="#cb213-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">6</span></span>
|
||
<span id="cb213-7"><a href="#cb213-7" aria-hidden="true" tabindex="-1"></a>safeNth <span class="dv">11</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">10</span>]</span>
|
||
<span id="cb213-8"><a href="#cb213-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span></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="cb214"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span id="cb214-1"><a href="#cb214-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Python</span></span>
|
||
<span id="cb214-2"><a href="#cb214-2" aria-hidden="true" tabindex="-1"></a>x <span class="op">=</span> op(val)</span>
|
||
<span id="cb214-3"><a href="#cb214-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> x:</span>
|
||
<span id="cb214-4"><a href="#cb214-4" aria-hidden="true" tabindex="-1"></a> f(x)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb215"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb215-1"><a href="#cb215-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Java</span></span>
|
||
<span id="cb215-2"><a href="#cb215-2" aria-hidden="true" tabindex="-1"></a><span class="bu">Object</span> x <span class="op">=</span> <span class="fu">op</span><span class="op">(</span>val<span class="op">);</span></span>
|
||
<span id="cb215-3"><a href="#cb215-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>x <span class="op">!=</span> <span class="kw">null</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb215-4"><a href="#cb215-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">f</span><span class="op">(</span>x<span class="op">);</span></span>
|
||
<span id="cb215-5"><a href="#cb215-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></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 data-number="13.2" 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="cb216"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb216-1"><a href="#cb216-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Logger definition</span></span>
|
||
<span id="cb216-2"><a href="#cb216-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Logger</span> a <span class="ot">=</span> <span class="dt">Logger</span> [<span class="dt">String</span>] a <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb216-3"><a href="#cb216-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb216-4"><a href="#cb216-4" aria-hidden="true" tabindex="-1"></a><span class="ot">getVal ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb216-5"><a href="#cb216-5" aria-hidden="true" tabindex="-1"></a>getVal (<span class="dt">Logger</span> _ a) <span class="ot">=</span> a</span>
|
||
<span id="cb216-6"><a href="#cb216-6" aria-hidden="true" tabindex="-1"></a><span class="ot">getLog ::</span> <span class="dt">Logger</span> a <span class="ot">-></span> [<span class="dt">String</span>]</span>
|
||
<span id="cb216-7"><a href="#cb216-7" aria-hidden="true" tabindex="-1"></a>getLog (<span class="dt">Logger</span> s _) <span class="ot">=</span> s</span>
|
||
<span id="cb216-8"><a href="#cb216-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb216-9"><a href="#cb216-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Primitive operations:</span></span>
|
||
<span id="cb216-10"><a href="#cb216-10" aria-hidden="true" tabindex="-1"></a><span class="ot">nomsg ::</span> a <span class="ot">-></span> <span class="dt">Logger</span> a</span>
|
||
<span id="cb216-11"><a href="#cb216-11" aria-hidden="true" tabindex="-1"></a>nomsg x <span class="ot">=</span> <span class="dt">Logger</span> [] x <span class="co">-- a value, no message</span></span>
|
||
<span id="cb216-12"><a href="#cb216-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb216-13"><a href="#cb216-13" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb216-14"><a href="#cb216-14" aria-hidden="true" tabindex="-1"></a>annotate s x <span class="ot">=</span> <span class="dt">Logger</span> [s] x <span class="co">-- a value and a message</span></span>
|
||
<span id="cb216-15"><a href="#cb216-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb216-16"><a href="#cb216-16" aria-hidden="true" tabindex="-1"></a><span class="ot">msg ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> ()</span>
|
||
<span id="cb216-17"><a href="#cb216-17" aria-hidden="true" tabindex="-1"></a>msg s <span class="ot">=</span> <span class="dt">Logger</span> [s] () <span class="co">-- just a message</span></span></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="cb217"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb217-1"><a href="#cb217-1" aria-hidden="true" tabindex="-1"></a><span class="ot">validateUser ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Bool</span></span>
|
||
<span id="cb217-2"><a href="#cb217-2" aria-hidden="true" tabindex="-1"></a>validateUser <span class="st">"paul.atreides"</span> <span class="ot">=</span> annotate <span class="st">"Valid user"</span> <span class="dt">True</span></span>
|
||
<span id="cb217-3"><a href="#cb217-3" aria-hidden="true" tabindex="-1"></a>validateUser <span class="st">"ninja"</span> <span class="ot">=</span> nomsg <span class="dt">True</span></span>
|
||
<span id="cb217-4"><a href="#cb217-4" aria-hidden="true" tabindex="-1"></a>validateUser u <span class="ot">=</span> annotate (<span class="st">"Invalid user: "</span><span class="op">++</span>u) <span class="dt">False</span></span>
|
||
<span id="cb217-5"><a href="#cb217-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb217-6"><a href="#cb217-6" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb217-7"><a href="#cb217-7" aria-hidden="true" tabindex="-1"></a>checkPassword <span class="st">"paul.atreides"</span> <span class="st">"muad'dib"</span> <span class="ot">=</span> annotate <span class="st">"Password ok"</span> <span class="dt">True</span></span>
|
||
<span id="cb217-8"><a href="#cb217-8" aria-hidden="true" tabindex="-1"></a>checkPassword <span class="st">"ninja"</span> <span class="st">""</span> <span class="ot">=</span> annotate <span class="st">"Password ok"</span> <span class="dt">True</span></span>
|
||
<span id="cb217-9"><a href="#cb217-9" aria-hidden="true" tabindex="-1"></a>checkPassword _ pass <span class="ot">=</span> annotate (<span class="st">"Password wrong: "</span><span class="op">++</span>pass) <span class="dt">False</span></span>
|
||
<span id="cb217-10"><a href="#cb217-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb217-11"><a href="#cb217-11" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb217-12"><a href="#cb217-12" aria-hidden="true" tabindex="-1"></a>login user password <span class="ot">=</span></span>
|
||
<span id="cb217-13"><a href="#cb217-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> validation <span class="ot">=</span> validateUser user</span>
|
||
<span id="cb217-14"><a href="#cb217-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="kw">if</span> (getVal validation)</span>
|
||
<span id="cb217-15"><a href="#cb217-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="kw">let</span> check <span class="ot">=</span> checkPassword user password</span>
|
||
<span id="cb217-16"><a href="#cb217-16" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="dt">Logger</span> (getLog validation <span class="op">++</span> getLog check) (getVal check)</span>
|
||
<span id="cb217-17"><a href="#cb217-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> validation</span></code></pre></div>
|
||
<div class="sourceCode" id="cb218"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb218-1"><a href="#cb218-1" aria-hidden="true" tabindex="-1"></a>login <span class="st">"paul.atreides"</span> <span class="st">"muad'dib"</span></span>
|
||
<span id="cb218-2"><a href="#cb218-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Logger</span> [<span class="st">"Valid user"</span>,<span class="st">"Password ok"</span>] <span class="dt">True</span></span>
|
||
<span id="cb218-3"><a href="#cb218-3" aria-hidden="true" tabindex="-1"></a>login <span class="st">"paul.atreides"</span> <span class="st">"arrakis"</span></span>
|
||
<span id="cb218-4"><a href="#cb218-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Logger</span> [<span class="st">"Valid user"</span>,<span class="st">"Password wrong: arrakis"</span>] <span class="dt">False</span></span>
|
||
<span id="cb218-5"><a href="#cb218-5" aria-hidden="true" tabindex="-1"></a>login <span class="st">"ninja"</span> <span class="st">""</span></span>
|
||
<span id="cb218-6"><a href="#cb218-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Logger</span> [<span class="st">"Password ok"</span>] <span class="dt">True</span></span>
|
||
<span id="cb218-7"><a href="#cb218-7" aria-hidden="true" tabindex="-1"></a>login <span class="st">"leto.atreides"</span> <span class="st">"paul"</span></span>
|
||
<span id="cb218-8"><a href="#cb218-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Logger</span> [<span class="st">"Invalid user: leto.atreides"</span>] <span class="dt">False</span></span></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="cb219"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb219-1"><a href="#cb219-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb219-2"><a href="#cb219-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Logger</span> la a <span class="op">#></span> f <span class="ot">=</span> <span class="kw">let</span> <span class="dt">Logger</span> lb b <span class="ot">=</span> f a <span class="co">-- feed value to next step</span></span>
|
||
<span id="cb219-3"><a href="#cb219-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="dt">Logger</span> (la<span class="op">++</span>lb) b <span class="co">-- bundle result with all messages</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb220"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb220-1"><a href="#cb220-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- square a number and log a message about it</span></span>
|
||
<span id="cb220-2"><a href="#cb220-2" aria-hidden="true" tabindex="-1"></a><span class="ot">square ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></span>
|
||
<span id="cb220-3"><a href="#cb220-3" aria-hidden="true" tabindex="-1"></a>square val <span class="ot">=</span> annotate (<span class="fu">show</span> val <span class="op">++</span> <span class="st">"^2"</span>) (val<span class="op">^</span><span class="dv">2</span>)</span>
|
||
<span id="cb220-4"><a href="#cb220-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb220-5"><a href="#cb220-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- add 1 to a number and log a message about it</span></span>
|
||
<span id="cb220-6"><a href="#cb220-6" aria-hidden="true" tabindex="-1"></a><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></span>
|
||
<span id="cb220-7"><a href="#cb220-7" aria-hidden="true" tabindex="-1"></a>add val <span class="ot">=</span> annotate (<span class="fu">show</span> val <span class="op">++</span> <span class="st">"+1"</span>) (val<span class="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb220-8"><a href="#cb220-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb220-9"><a href="#cb220-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- double a number and log a message about it</span></span>
|
||
<span id="cb220-10"><a href="#cb220-10" aria-hidden="true" tabindex="-1"></a><span class="ot">double ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></span>
|
||
<span id="cb220-11"><a href="#cb220-11" aria-hidden="true" tabindex="-1"></a>double val <span class="ot">=</span> annotate (<span class="fu">show</span> val <span class="op">++</span> <span class="st">"*2"</span>) (val<span class="op">*</span><span class="dv">2</span>)</span>
|
||
<span id="cb220-12"><a href="#cb220-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb220-13"><a href="#cb220-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- compute the expression 2*(x^2+1) with logging</span></span>
|
||
<span id="cb220-14"><a href="#cb220-14" aria-hidden="true" tabindex="-1"></a><span class="ot">compute ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Logger</span> <span class="dt">Int</span></span>
|
||
<span id="cb220-15"><a href="#cb220-15" aria-hidden="true" tabindex="-1"></a>compute x <span class="ot">=</span></span>
|
||
<span id="cb220-16"><a href="#cb220-16" aria-hidden="true" tabindex="-1"></a> square x</span>
|
||
<span id="cb220-17"><a href="#cb220-17" aria-hidden="true" tabindex="-1"></a> <span class="op">#></span> add</span>
|
||
<span id="cb220-18"><a href="#cb220-18" aria-hidden="true" tabindex="-1"></a> <span class="op">#></span> double</span></code></pre></div>
|
||
<div class="sourceCode" id="cb221"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb221-1"><a href="#cb221-1" aria-hidden="true" tabindex="-1"></a>compute <span class="dv">3</span></span>
|
||
<span id="cb221-2"><a href="#cb221-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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></span></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="cb222"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb222-1"><a href="#cb222-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb222-2"><a href="#cb222-2" aria-hidden="true" tabindex="-1"></a>login user password <span class="ot">=</span></span>
|
||
<span id="cb222-3"><a href="#cb222-3" aria-hidden="true" tabindex="-1"></a> validateUser user</span>
|
||
<span id="cb222-4"><a href="#cb222-4" aria-hidden="true" tabindex="-1"></a> <span class="op">#></span></span>
|
||
<span id="cb222-5"><a href="#cb222-5" aria-hidden="true" tabindex="-1"></a> \valid <span class="ot">-></span> <span class="kw">if</span> valid <span class="kw">then</span> checkPassword user password</span>
|
||
<span id="cb222-6"><a href="#cb222-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> nomsg <span class="dt">False</span></span></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="cb223"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb223-1"><a href="#cb223-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- sometimes you don't need the previous value:</span></span>
|
||
<span id="cb223-2"><a href="#cb223-2" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb223-3"><a href="#cb223-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Logger</span> la _ <span class="op">##></span> <span class="dt">Logger</span> lb b <span class="ot">=</span> <span class="dt">Logger</span> (la<span class="op">++</span>lb) b</span>
|
||
<span id="cb223-4"><a href="#cb223-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb223-5"><a href="#cb223-5" aria-hidden="true" tabindex="-1"></a><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]</span>
|
||
<span id="cb223-6"><a href="#cb223-6" aria-hidden="true" tabindex="-1"></a>filterLog f [] <span class="ot">=</span> nomsg []</span>
|
||
<span id="cb223-7"><a href="#cb223-7" aria-hidden="true" tabindex="-1"></a>filterLog f (x<span class="op">:</span>xs)</span>
|
||
<span id="cb223-8"><a href="#cb223-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> f x <span class="ot">=</span> msg (<span class="st">"keeping "</span><span class="op">++</span><span class="fu">show</span> x) <span class="op">##></span> filterLog f xs <span class="op">#></span> (\xs' <span class="ot">-></span> nomsg (x<span class="op">:</span>xs'))</span>
|
||
<span id="cb223-9"><a href="#cb223-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> msg (<span class="st">"dropping "</span><span class="op">++</span><span class="fu">show</span> x) <span class="op">##></span> filterLog f xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb224"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb224-1"><a href="#cb224-1" aria-hidden="true" tabindex="-1"></a>filterLog (<span class="op">></span><span class="dv">0</span>) [<span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb224-2"><a href="#cb224-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]</span></code></pre></div>
|
||
<h2 data-number="13.3" 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="cb225"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb225-1"><a href="#cb225-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb225-2"><a href="#cb225-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb225-3"><a href="#cb225-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Bank</span> <span class="ot">=</span> <span class="dt">Bank</span> (<span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span>)</span>
|
||
<span id="cb225-4"><a href="#cb225-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span></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="cb226"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb226-1"><a href="#cb226-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Apply a function to one value in a map</span></span>
|
||
<span id="cb226-2"><a href="#cb226-2" aria-hidden="true" tabindex="-1"></a>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</span></code></pre></div>
|
||
<div class="sourceCode" id="cb227"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb227-1"><a href="#cb227-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb227-2"><a href="#cb227-2" aria-hidden="true" tabindex="-1"></a>deposit accountName amount (<span class="dt">Bank</span> accounts) <span class="ot">=</span></span>
|
||
<span id="cb227-3"><a href="#cb227-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Bank</span> (Map.adjust (\x <span class="ot">-></span> x<span class="op">+</span>amount) accountName accounts)</span></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="cb228"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb228-1"><a href="#cb228-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Fetch the value corresponding to a key from a map,</span></span>
|
||
<span id="cb228-2"><a href="#cb228-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- or a default value in case the key does not exist</span></span>
|
||
<span id="cb228-3"><a href="#cb228-3" aria-hidden="true" tabindex="-1"></a>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</span></code></pre></div>
|
||
<div class="sourceCode" id="cb229"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb229-1"><a href="#cb229-1" aria-hidden="true" tabindex="-1"></a><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>)</span>
|
||
<span id="cb229-2"><a href="#cb229-2" aria-hidden="true" tabindex="-1"></a>withdraw accountName amount (<span class="dt">Bank</span> accounts) <span class="ot">=</span></span>
|
||
<span id="cb229-3"><a href="#cb229-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> <span class="co">-- balance is 0 for a nonexistant account</span></span>
|
||
<span id="cb229-4"><a href="#cb229-4" aria-hidden="true" tabindex="-1"></a> balance <span class="ot">=</span> Map.findWithDefault <span class="dv">0</span> accountName accounts</span>
|
||
<span id="cb229-5"><a href="#cb229-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- can't withdraw over balance</span></span>
|
||
<span id="cb229-6"><a href="#cb229-6" aria-hidden="true" tabindex="-1"></a> withdrawal <span class="ot">=</span> <span class="fu">min</span> amount balance</span>
|
||
<span id="cb229-7"><a href="#cb229-7" aria-hidden="true" tabindex="-1"></a> newAccounts <span class="ot">=</span> Map.adjust (\x <span class="ot">-></span> x<span class="op">-</span>withdrawal) accountName accounts</span>
|
||
<span id="cb229-8"><a href="#cb229-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> (withdrawal, <span class="dt">Bank</span> newAccounts)</span></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="cb230"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb230-1"><a href="#cb230-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb230-2"><a href="#cb230-2" aria-hidden="true" tabindex="-1"></a>share from to1 to2 bank <span class="ot">=</span></span>
|
||
<span id="cb230-3"><a href="#cb230-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> (amount,bank1) <span class="ot">=</span> withdraw from <span class="dv">100</span> bank</span>
|
||
<span id="cb230-4"><a href="#cb230-4" aria-hidden="true" tabindex="-1"></a> half <span class="ot">=</span> <span class="fu">div</span> amount <span class="dv">2</span></span>
|
||
<span id="cb230-5"><a href="#cb230-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- carefully preserve all money, even if amount was an odd number</span></span>
|
||
<span id="cb230-6"><a href="#cb230-6" aria-hidden="true" tabindex="-1"></a> rest <span class="ot">=</span> amount<span class="op">-</span>half</span>
|
||
<span id="cb230-7"><a href="#cb230-7" aria-hidden="true" tabindex="-1"></a> bank2 <span class="ot">=</span> deposit to1 half bank1</span>
|
||
<span id="cb230-8"><a href="#cb230-8" aria-hidden="true" tabindex="-1"></a> bank3 <span class="ot">=</span> deposit to2 rest bank2</span>
|
||
<span id="cb230-9"><a href="#cb230-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> bank3</span></code></pre></div>
|
||
<div class="sourceCode" id="cb231"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb231-1"><a href="#cb231-1" aria-hidden="true" tabindex="-1"></a>share <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span></span>
|
||
<span id="cb231-2"><a href="#cb231-2" aria-hidden="true" tabindex="-1"></a> (<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>)]))</span>
|
||
<span id="cb231-3"><a href="#cb231-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)])</span>
|
||
<span id="cb231-4"><a href="#cb231-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb231-5"><a href="#cb231-5" aria-hidden="true" tabindex="-1"></a>share <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span></span>
|
||
<span id="cb231-6"><a href="#cb231-6" aria-hidden="true" tabindex="-1"></a> (<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>)]))</span>
|
||
<span id="cb231-7"><a href="#cb231-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)])</span></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="cb232"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb232-1"><a href="#cb232-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- `BankOp a` is an operation that transforms a Bank value,</span></span>
|
||
<span id="cb232-2"><a href="#cb232-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- while returning a value of type `a`</span></span>
|
||
<span id="cb232-3"><a href="#cb232-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">BankOp</span> a <span class="ot">=</span> <span class="dt">BankOp</span> (<span class="dt">Bank</span> <span class="ot">-></span> (a,<span class="dt">Bank</span>))</span>
|
||
<span id="cb232-4"><a href="#cb232-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb232-5"><a href="#cb232-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- running a BankOp on a Bank</span></span>
|
||
<span id="cb232-6"><a href="#cb232-6" aria-hidden="true" tabindex="-1"></a><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>)</span>
|
||
<span id="cb232-7"><a href="#cb232-7" aria-hidden="true" tabindex="-1"></a>runBankOp (<span class="dt">BankOp</span> f) bank <span class="ot">=</span> f bank</span>
|
||
<span id="cb232-8"><a href="#cb232-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb232-9"><a href="#cb232-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Running one BankOp after another</span></span>
|
||
<span id="cb232-10"><a href="#cb232-10" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb232-11"><a href="#cb232-11" aria-hidden="true" tabindex="-1"></a>op1 <span class="op">+>></span> op2 <span class="ot">=</span> <span class="dt">BankOp</span> combined</span>
|
||
<span id="cb232-12"><a href="#cb232-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> combined bank <span class="ot">=</span> <span class="kw">let</span> (_,bank1) <span class="ot">=</span> runBankOp op1 bank</span>
|
||
<span id="cb232-13"><a href="#cb232-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> runBankOp op2 bank1</span>
|
||
<span id="cb232-14"><a href="#cb232-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb232-15"><a href="#cb232-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Running a parameterized BankOp, using the value returned</span></span>
|
||
<span id="cb232-16"><a href="#cb232-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- by a previous BankOp. The implementation is a bit tricky</span></span>
|
||
<span id="cb232-17"><a href="#cb232-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- but it's enough to understand how +> is used for now.</span></span>
|
||
<span id="cb232-18"><a href="#cb232-18" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb232-19"><a href="#cb232-19" aria-hidden="true" tabindex="-1"></a>op <span class="op">+></span> parameterized <span class="ot">=</span> <span class="dt">BankOp</span> combined</span>
|
||
<span id="cb232-20"><a href="#cb232-20" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> combined bank <span class="ot">=</span> <span class="kw">let</span> (a,bank1) <span class="ot">=</span> runBankOp op bank</span>
|
||
<span id="cb232-21"><a href="#cb232-21" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> runBankOp (parameterized a) bank1</span>
|
||
<span id="cb232-22"><a href="#cb232-22" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb232-23"><a href="#cb232-23" aria-hidden="true" tabindex="-1"></a><span class="co">-- Make a BankOp out of deposit.</span></span>
|
||
<span id="cb232-24"><a href="#cb232-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- There is no return value so we use ().</span></span>
|
||
<span id="cb232-25"><a href="#cb232-25" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb232-26"><a href="#cb232-26" aria-hidden="true" tabindex="-1"></a>depositOp accountName amount <span class="ot">=</span> <span class="dt">BankOp</span> depositHelper</span>
|
||
<span id="cb232-27"><a href="#cb232-27" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> depositHelper bank <span class="ot">=</span> ((), deposit accountName amount bank)</span>
|
||
<span id="cb232-28"><a href="#cb232-28" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb232-29"><a href="#cb232-29" aria-hidden="true" tabindex="-1"></a><span class="co">-- Make a BankOp out of withdraw. Note how</span></span>
|
||
<span id="cb232-30"><a href="#cb232-30" aria-hidden="true" tabindex="-1"></a><span class="co">-- withdraw accountName amount :: Bank -> (Int,Bank)</span></span>
|
||
<span id="cb232-31"><a href="#cb232-31" aria-hidden="true" tabindex="-1"></a><span class="co">-- is almost a BankOp already!</span></span>
|
||
<span id="cb232-32"><a href="#cb232-32" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb232-33"><a href="#cb232-33" aria-hidden="true" tabindex="-1"></a>withdrawOp accountName amount <span class="ot">=</span> <span class="dt">BankOp</span> (withdraw accountName amount)</span></code></pre></div>
|
||
<p>Let’s see how chaining works with these bank operations.</p>
|
||
<div class="sourceCode" id="cb233"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb233-1"><a href="#cb233-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> bank <span class="ot">=</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>)])</span>
|
||
<span id="cb233-2"><a href="#cb233-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-3"><a href="#cb233-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Running a number of operations using +>></span></span>
|
||
<span id="cb233-4"><a href="#cb233-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-5"><a href="#cb233-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span>) bank</span>
|
||
<span id="cb233-6"><a href="#cb233-6" aria-hidden="true" tabindex="-1"></a>((),<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>)]))</span>
|
||
<span id="cb233-7"><a href="#cb233-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-8"><a href="#cb233-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span> <span class="op">+>></span> depositOp <span class="st">"grace"</span> <span class="dv">1</span>) bank</span>
|
||
<span id="cb233-9"><a href="#cb233-9" aria-hidden="true" tabindex="-1"></a>((),<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>)]))</span>
|
||
<span id="cb233-10"><a href="#cb233-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-11"><a href="#cb233-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> runBankOp (depositOp <span class="st">"edsger"</span> <span class="dv">1</span> <span class="op">+>></span> depositOp <span class="st">"grace"</span> <span class="dv">1</span> <span class="op">+>></span> withdrawOp <span class="st">"edsger"</span> <span class="dv">11</span>) bank</span>
|
||
<span id="cb233-12"><a href="#cb233-12" aria-hidden="true" tabindex="-1"></a>(<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>)]))</span>
|
||
<span id="cb233-13"><a href="#cb233-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-14"><a href="#cb233-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- Using +> to implement a transfer from one account to the other:</span></span>
|
||
<span id="cb233-15"><a href="#cb233-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-16"><a href="#cb233-16" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> runBankOp (withdrawOp <span class="st">"edsger"</span> <span class="dv">5</span> <span class="op">+></span> depositOp <span class="st">"grace"</span>) bank</span>
|
||
<span id="cb233-17"><a href="#cb233-17" aria-hidden="true" tabindex="-1"></a>((),<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>)]))</span>
|
||
<span id="cb233-18"><a href="#cb233-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb233-19"><a href="#cb233-19" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> runBankOp (withdrawOp <span class="st">"edsger"</span> <span class="dv">100</span> <span class="op">+></span> depositOp <span class="st">"grace"</span>) bank</span>
|
||
<span id="cb233-20"><a href="#cb233-20" aria-hidden="true" tabindex="-1"></a>((),<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>)]))</span></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="cb234"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb234-1"><a href="#cb234-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- distribute amount to two accounts</span></span>
|
||
<span id="cb234-2"><a href="#cb234-2" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb234-3"><a href="#cb234-3" aria-hidden="true" tabindex="-1"></a>distributeOp to1 to2 amount <span class="ot">=</span></span>
|
||
<span id="cb234-4"><a href="#cb234-4" aria-hidden="true" tabindex="-1"></a> depositOp to1 half</span>
|
||
<span id="cb234-5"><a href="#cb234-5" aria-hidden="true" tabindex="-1"></a> <span class="op">+>></span></span>
|
||
<span id="cb234-6"><a href="#cb234-6" aria-hidden="true" tabindex="-1"></a> depositOp to2 rest</span>
|
||
<span id="cb234-7"><a href="#cb234-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> half <span class="ot">=</span> <span class="fu">div</span> amount <span class="dv">2</span></span>
|
||
<span id="cb234-8"><a href="#cb234-8" aria-hidden="true" tabindex="-1"></a> rest <span class="ot">=</span> amount <span class="op">-</span> half</span>
|
||
<span id="cb234-9"><a href="#cb234-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb234-10"><a href="#cb234-10" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb234-11"><a href="#cb234-11" aria-hidden="true" tabindex="-1"></a>shareOp from to1 to2 <span class="ot">=</span></span>
|
||
<span id="cb234-12"><a href="#cb234-12" aria-hidden="true" tabindex="-1"></a> withdrawOp from <span class="dv">100</span></span>
|
||
<span id="cb234-13"><a href="#cb234-13" aria-hidden="true" tabindex="-1"></a> <span class="op">+></span></span>
|
||
<span id="cb234-14"><a href="#cb234-14" aria-hidden="true" tabindex="-1"></a> distributeOp to1 to2</span></code></pre></div>
|
||
<div class="sourceCode" id="cb235"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb235-1"><a href="#cb235-1" aria-hidden="true" tabindex="-1"></a>runBankOp (shareOp <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span>)</span>
|
||
<span id="cb235-2"><a href="#cb235-2" aria-hidden="true" tabindex="-1"></a> (<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>)]))</span>
|
||
<span id="cb235-3"><a href="#cb235-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)]))</span>
|
||
<span id="cb235-4"><a href="#cb235-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb235-5"><a href="#cb235-5" aria-hidden="true" tabindex="-1"></a>runBankOp (shareOp <span class="st">"wotan"</span> <span class="st">"siegfried"</span> <span class="st">"brunhilde"</span>)</span>
|
||
<span id="cb235-6"><a href="#cb235-6" aria-hidden="true" tabindex="-1"></a> (<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>)]))</span>
|
||
<span id="cb235-7"><a href="#cb235-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)]))</span></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 data-number="13.4" 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="cb236"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb236-1"><a href="#cb236-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb236-2"><a href="#cb236-2" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb236-3"><a href="#cb236-3" aria-hidden="true" tabindex="-1"></a><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</span></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="cb237"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb237-1"><a href="#cb237-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="kw">where</span></span>
|
||
<span id="cb237-2"><a href="#cb237-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> (>>=) ::</span> m a <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m b</span></code></pre></div>
|
||
<p>There are some additional operations in <code>Monad</code> too:</p>
|
||
<div class="sourceCode" id="cb238"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb238-1"><a href="#cb238-1" aria-hidden="true" tabindex="-1"></a> <span class="co">-- lift a normal value into the monad</span></span>
|
||
<span id="cb238-2"><a href="#cb238-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> return ::</span> a <span class="ot">-></span> m a</span>
|
||
<span id="cb238-3"><a href="#cb238-3" aria-hidden="true" tabindex="-1"></a> <span class="co">-- simpler chaining (like our ##>)</span></span>
|
||
<span id="cb238-4"><a href="#cb238-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> (>>) ::</span> m a <span class="ot">-></span> m b <span class="ot">-></span> m b</span>
|
||
<span id="cb238-5"><a href="#cb238-5" aria-hidden="true" tabindex="-1"></a> a <span class="op">>></span> b <span class="ot">=</span> a <span class="op">>>=</span> \_ <span class="ot">-></span> b <span class="co">-- remember: _ means ignored argument</span></span></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="cb239"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb239-1"><a href="#cb239-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span><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</span>
|
||
<span id="cb239-2"><a href="#cb239-2" aria-hidden="true" tabindex="-1"></a><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</span></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="cb240"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb240-1"><a href="#cb240-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb240-2"><a href="#cb240-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- if we failed, don't even bother running the next step</span></span>
|
||
<span id="cb240-3"><a href="#cb240-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span> <span class="op">>>=</span> _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb240-4"><a href="#cb240-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- otherwise run the next step</span></span>
|
||
<span id="cb240-5"><a href="#cb240-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> x <span class="op">>>=</span> f <span class="ot">=</span> f x</span></code></pre></div>
|
||
<h2 data-number="13.5" 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="cb241"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb241-1"><a href="#cb241-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
|
||
<span id="cb241-2"><a href="#cb241-2" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Just</span> x) <span class="op">>>=</span> k <span class="ot">=</span> k x</span>
|
||
<span id="cb241-3"><a href="#cb241-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="op">>>=</span> _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb241-4"><a href="#cb241-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb241-5"><a href="#cb241-5" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Just</span> _) <span class="op">>></span> k <span class="ot">=</span> k</span>
|
||
<span id="cb241-6"><a href="#cb241-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="op">>></span> _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb241-7"><a href="#cb241-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb241-8"><a href="#cb241-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> x <span class="ot">=</span> <span class="dt">Just</span> x</span></code></pre></div>
|
||
<div class="sourceCode" id="cb242"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb242-1"><a href="#cb242-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">1</span> <span class="op">>>=</span> \x <span class="ot">-></span> <span class="fu">return</span> (x<span class="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb242-2"><a href="#cb242-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">2</span></span>
|
||
<span id="cb242-3"><a href="#cb242-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="op">>>=</span> (\x <span class="ot">-></span> <span class="fu">return</span> (<span class="fu">length</span> x)) <span class="op">>>=</span> (\x <span class="ot">-></span> <span class="fu">return</span> (x<span class="op">+</span><span class="dv">1</span>))</span>
|
||
<span id="cb242-4"><a href="#cb242-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">6</span></span>
|
||
<span id="cb242-5"><a href="#cb242-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="op">>>=</span> \x <span class="ot">-></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb242-6"><a href="#cb242-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb242-7"><a href="#cb242-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"HELLO"</span> <span class="op">>></span> <span class="dt">Just</span> <span class="dv">2</span></span>
|
||
<span id="cb242-8"><a href="#cb242-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">2</span></span>
|
||
<span id="cb242-9"><a href="#cb242-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">2</span> <span class="op">>></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb242-10"><a href="#cb242-10" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span></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="cb243"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb243-1"><a href="#cb243-1" aria-hidden="true" tabindex="-1"></a><span class="ot">stealSecret ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb243-2"><a href="#cb243-2" aria-hidden="true" tabindex="-1"></a>stealSecret password <span class="ot">=</span></span>
|
||
<span id="cb243-3"><a href="#cb243-3" aria-hidden="true" tabindex="-1"></a> login password <span class="op">>>=</span></span>
|
||
<span id="cb243-4"><a href="#cb243-4" aria-hidden="true" tabindex="-1"></a> secret <span class="op">>>=</span></span>
|
||
<span id="cb243-5"><a href="#cb243-5" aria-hidden="true" tabindex="-1"></a> decorate</span>
|
||
<span id="cb243-6"><a href="#cb243-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> decorate s <span class="ot">=</span> <span class="fu">return</span> (<span class="st">"Stole secret: "</span><span class="op">++</span>s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb244"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb244-1"><a href="#cb244-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Set the value of key to val in the given key-value list,</span></span>
|
||
<span id="cb244-2"><a href="#cb244-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- but only if val is larger than the current value!</span></span>
|
||
<span id="cb244-3"><a href="#cb244-3" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb244-4"><a href="#cb244-4" aria-hidden="true" tabindex="-1"></a>increase key val assocs <span class="ot">=</span></span>
|
||
<span id="cb244-5"><a href="#cb244-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">lookup</span> key assocs <span class="op">>>=</span></span>
|
||
<span id="cb244-6"><a href="#cb244-6" aria-hidden="true" tabindex="-1"></a> check <span class="op">>>=</span></span>
|
||
<span id="cb244-7"><a href="#cb244-7" aria-hidden="true" tabindex="-1"></a> buildResult</span>
|
||
<span id="cb244-8"><a href="#cb244-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> check x</span>
|
||
<span id="cb244-9"><a href="#cb244-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> val <span class="op"><</span> x <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb244-10"><a href="#cb244-10" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">return</span> x</span>
|
||
<span id="cb244-11"><a href="#cb244-11" aria-hidden="true" tabindex="-1"></a> buildResult x <span class="ot">=</span> <span class="fu">return</span> ((key,val) <span class="op">:</span> delete (key,x) assocs)</span></code></pre></div>
|
||
<h2 data-number="13.6" 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="cb245"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb245-1"><a href="#cb245-1" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> op1 <span class="op">>>=</span> continue</span>
|
||
<span id="cb245-2"><a href="#cb245-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> continue x <span class="ot">=</span> op2 <span class="op">>></span> op3 <span class="op">>>=</span> continue2 x</span>
|
||
<span id="cb245-3"><a href="#cb245-3" aria-hidden="true" tabindex="-1"></a> continue2 x y <span class="ot">=</span> op4 <span class="op">>></span> op5 x y</span></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="cb246"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb246-1"><a href="#cb246-1" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> op1 <span class="op">>>=</span> (\x <span class="ot">-></span></span>
|
||
<span id="cb246-2"><a href="#cb246-2" aria-hidden="true" tabindex="-1"></a> op2 <span class="op">>></span></span>
|
||
<span id="cb246-3"><a href="#cb246-3" aria-hidden="true" tabindex="-1"></a> op3 <span class="op">>>=</span> (\y <span class="ot">-></span></span>
|
||
<span id="cb246-4"><a href="#cb246-4" aria-hidden="true" tabindex="-1"></a> op4 <span class="op">>></span></span>
|
||
<span id="cb246-5"><a href="#cb246-5" aria-hidden="true" tabindex="-1"></a> op5 x y))</span></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="cb247"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb247-1"><a href="#cb247-1" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> op1 <span class="op">>>=</span> \x <span class="ot">-></span></span>
|
||
<span id="cb247-2"><a href="#cb247-2" aria-hidden="true" tabindex="-1"></a> op2 <span class="op">>></span></span>
|
||
<span id="cb247-3"><a href="#cb247-3" aria-hidden="true" tabindex="-1"></a> op3 <span class="op">>>=</span> \y <span class="ot">-></span></span>
|
||
<span id="cb247-4"><a href="#cb247-4" aria-hidden="true" tabindex="-1"></a> op4 <span class="op">>></span></span>
|
||
<span id="cb247-5"><a href="#cb247-5" aria-hidden="true" tabindex="-1"></a> op5 x y</span></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="cb248"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb248-1"><a href="#cb248-1" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> <span class="kw">do</span> x <span class="ot"><-</span> op1</span>
|
||
<span id="cb248-2"><a href="#cb248-2" aria-hidden="true" tabindex="-1"></a> op2</span>
|
||
<span id="cb248-3"><a href="#cb248-3" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> op3</span>
|
||
<span id="cb248-4"><a href="#cb248-4" aria-hidden="true" tabindex="-1"></a> op4</span>
|
||
<span id="cb248-5"><a href="#cb248-5" aria-hidden="true" tabindex="-1"></a> op5 x y</span></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="cb249"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb249-1"><a href="#cb249-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> x <span class="ot"><-</span> op a <span class="op">~~~></span> op a <span class="op">>>=</span> \x <span class="ot">-></span> <span class="kw">do</span> <span class="op">...</span></span>
|
||
<span id="cb249-2"><a href="#cb249-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb250"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb250-1"><a href="#cb250-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> op a <span class="op">~~~></span> op a <span class="op">>></span> <span class="kw">do</span> <span class="op">...</span></span>
|
||
<span id="cb250-2"><a href="#cb250-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb251"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb251-1"><a href="#cb251-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> <span class="kw">let</span> x <span class="ot">=</span> expr <span class="op">~~~></span> <span class="kw">let</span> x <span class="ot">=</span> expr <span class="kw">in</span> <span class="kw">do</span> <span class="op">...</span></span>
|
||
<span id="cb251-2"><a href="#cb251-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb252"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb252-1"><a href="#cb252-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> finalOp <span class="op">~~~></span> finalOp</span></code></pre></div>
|
||
<p>Here’s <code>safeNth</code> using do notation:</p>
|
||
<div class="sourceCode" id="cb253"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb253-1"><a href="#cb253-1" aria-hidden="true" tabindex="-1"></a><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb253-2"><a href="#cb253-2" aria-hidden="true" tabindex="-1"></a>safeHead [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb253-3"><a href="#cb253-3" aria-hidden="true" tabindex="-1"></a>safeHead (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb253-4"><a href="#cb253-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb253-5"><a href="#cb253-5" aria-hidden="true" tabindex="-1"></a><span class="ot">safeTail ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</span>
|
||
<span id="cb253-6"><a href="#cb253-6" aria-hidden="true" tabindex="-1"></a>safeTail [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb253-7"><a href="#cb253-7" aria-hidden="true" tabindex="-1"></a>safeTail (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> xs</span>
|
||
<span id="cb253-8"><a href="#cb253-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb253-9"><a href="#cb253-9" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb253-10"><a href="#cb253-10" aria-hidden="true" tabindex="-1"></a>safeNth <span class="dv">0</span> xs <span class="ot">=</span> safeHead xs</span>
|
||
<span id="cb253-11"><a href="#cb253-11" aria-hidden="true" tabindex="-1"></a>safeNth n xs <span class="ot">=</span> <span class="kw">do</span> t <span class="ot"><-</span> safeTail xs</span>
|
||
<span id="cb253-12"><a href="#cb253-12" aria-hidden="true" tabindex="-1"></a> safeNth (n<span class="op">-</span><span class="dv">1</span>) t</span></code></pre></div>
|
||
<p>Here is <code>increase</code> one last time, now with do notation</p>
|
||
<div class="sourceCode" id="cb254"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb254-1"><a href="#cb254-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Set the value of key to val in the given key-value list,</span></span>
|
||
<span id="cb254-2"><a href="#cb254-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- but only if val is larger than the current value!</span></span>
|
||
<span id="cb254-3"><a href="#cb254-3" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb254-4"><a href="#cb254-4" aria-hidden="true" tabindex="-1"></a>increase key val assocs <span class="ot">=</span></span>
|
||
<span id="cb254-5"><a href="#cb254-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">do</span> oldVal <span class="ot"><-</span> <span class="fu">lookup</span> key assocs</span>
|
||
<span id="cb254-6"><a href="#cb254-6" aria-hidden="true" tabindex="-1"></a> check oldVal</span>
|
||
<span id="cb254-7"><a href="#cb254-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> ((key,val) <span class="op">:</span> delete (key,oldVal) assocs)</span>
|
||
<span id="cb254-8"><a href="#cb254-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> check x</span>
|
||
<span id="cb254-9"><a href="#cb254-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> val <span class="op"><</span> x <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb254-10"><a href="#cb254-10" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="fu">return</span> x</span></code></pre></div>
|
||
<h2 data-number="13.7" 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="cb255"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb255-1"><a href="#cb255-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Control.Monad</span></span>
|
||
<span id="cb255-2"><a href="#cb255-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb255-3"><a href="#cb255-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Logger</span> a <span class="ot">=</span> <span class="dt">Logger</span> [<span class="dt">String</span>] a <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb255-4"><a href="#cb255-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb255-5"><a href="#cb255-5" aria-hidden="true" tabindex="-1"></a><span class="ot">msg ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Logger</span> ()</span>
|
||
<span id="cb255-6"><a href="#cb255-6" aria-hidden="true" tabindex="-1"></a>msg s <span class="ot">=</span> <span class="dt">Logger</span> [s] ()</span>
|
||
<span id="cb255-7"><a href="#cb255-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb255-8"><a href="#cb255-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- The Functor instance just maps over the stored value</span></span>
|
||
<span id="cb255-9"><a href="#cb255-9" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Logger</span> <span class="kw">where</span></span>
|
||
<span id="cb255-10"><a href="#cb255-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f (<span class="dt">Logger</span> <span class="fu">log</span> x) <span class="ot">=</span> <span class="dt">Logger</span> <span class="fu">log</span> (f x)</span>
|
||
<span id="cb255-11"><a href="#cb255-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb255-12"><a href="#cb255-12" aria-hidden="true" tabindex="-1"></a><span class="co">-- This is an Applicative instance that works for any</span></span>
|
||
<span id="cb255-13"><a href="#cb255-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- monad, you can just ignore it for now. We'll get back</span></span>
|
||
<span id="cb255-14"><a href="#cb255-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- to Applicative later.</span></span>
|
||
<span id="cb255-15"><a href="#cb255-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Logger</span> <span class="kw">where</span></span>
|
||
<span id="cb255-16"><a href="#cb255-16" aria-hidden="true" tabindex="-1"></a> <span class="fu">pure</span> <span class="ot">=</span> <span class="fu">return</span></span>
|
||
<span id="cb255-17"><a href="#cb255-17" aria-hidden="true" tabindex="-1"></a> (<span class="op"><*></span>) <span class="ot">=</span> ap</span>
|
||
<span id="cb255-18"><a href="#cb255-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb255-19"><a href="#cb255-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- Finally, the Monad instance</span></span>
|
||
<span id="cb255-20"><a href="#cb255-20" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Logger</span> <span class="kw">where</span></span>
|
||
<span id="cb255-21"><a href="#cb255-21" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> x <span class="ot">=</span> <span class="dt">Logger</span> [] x</span>
|
||
<span id="cb255-22"><a href="#cb255-22" aria-hidden="true" tabindex="-1"></a> <span class="dt">Logger</span> la a <span class="op">>>=</span> f <span class="ot">=</span> <span class="dt">Logger</span> (la<span class="op">++</span>lb) b</span>
|
||
<span id="cb255-23"><a href="#cb255-23" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> <span class="dt">Logger</span> lb b <span class="ot">=</span> f a</span></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="cb256"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb256-1"><a href="#cb256-1" aria-hidden="true" tabindex="-1"></a><span class="ot">nomsg ::</span> a <span class="ot">-></span> <span class="dt">Logger</span> a</span>
|
||
<span id="cb256-2"><a href="#cb256-2" aria-hidden="true" tabindex="-1"></a>nomsg x <span class="ot">=</span> <span class="fu">return</span> x</span>
|
||
<span id="cb256-3"><a href="#cb256-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb256-4"><a href="#cb256-4" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb256-5"><a href="#cb256-5" aria-hidden="true" tabindex="-1"></a>annotate s x <span class="ot">=</span> msg s <span class="op">>></span> <span class="fu">return</span> x</span></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="cb257"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb257-1"><a href="#cb257-1" aria-hidden="true" tabindex="-1"></a>compute x <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb257-2"><a href="#cb257-2" aria-hidden="true" tabindex="-1"></a> a <span class="ot"><-</span> annotate <span class="st">"^2"</span> (x<span class="op">*</span>x)</span>
|
||
<span id="cb257-3"><a href="#cb257-3" aria-hidden="true" tabindex="-1"></a> b <span class="ot"><-</span> annotate <span class="st">"+1"</span> (a<span class="op">+</span><span class="dv">1</span>)</span>
|
||
<span id="cb257-4"><a href="#cb257-4" aria-hidden="true" tabindex="-1"></a> annotate <span class="st">"*2"</span> (b<span class="op">*</span><span class="dv">2</span>)</span>
|
||
<span id="cb257-5"><a href="#cb257-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb257-6"><a href="#cb257-6" aria-hidden="true" tabindex="-1"></a><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]</span>
|
||
<span id="cb257-7"><a href="#cb257-7" aria-hidden="true" tabindex="-1"></a>filterLog f [] <span class="ot">=</span> <span class="fu">return</span> []</span>
|
||
<span id="cb257-8"><a href="#cb257-8" aria-hidden="true" tabindex="-1"></a>filterLog f (x<span class="op">:</span>xs)</span>
|
||
<span id="cb257-9"><a href="#cb257-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> f x <span class="ot">=</span> <span class="kw">do</span> msg (<span class="st">"keeping "</span><span class="op">++</span><span class="fu">show</span> x)</span>
|
||
<span id="cb257-10"><a href="#cb257-10" aria-hidden="true" tabindex="-1"></a> xs' <span class="ot"><-</span> filterLog f xs</span>
|
||
<span id="cb257-11"><a href="#cb257-11" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (x<span class="op">:</span>xs')</span>
|
||
<span id="cb257-12"><a href="#cb257-12" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="kw">do</span> msg (<span class="st">"dropping "</span><span class="op">++</span><span class="fu">show</span> x)</span>
|
||
<span id="cb257-13"><a href="#cb257-13" aria-hidden="true" tabindex="-1"></a> filterLog f xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb258"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb258-1"><a href="#cb258-1" aria-hidden="true" tabindex="-1"></a>compute <span class="dv">3</span></span>
|
||
<span id="cb258-2"><a href="#cb258-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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></span>
|
||
<span id="cb258-3"><a href="#cb258-3" aria-hidden="true" tabindex="-1"></a>filterLog (<span class="op">></span><span class="dv">0</span>) [<span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb258-4"><a href="#cb258-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]</span></code></pre></div>
|
||
<h2 data-number="13.8" 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="cb259"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb259-1"><a href="#cb259-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">State</span> s a <span class="ot">=</span> <span class="dt">State</span> (s <span class="ot">-></span> (a,s))</span>
|
||
<span id="cb259-2"><a href="#cb259-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-3"><a href="#cb259-3" aria-hidden="true" tabindex="-1"></a>runState (<span class="dt">State</span> f) s <span class="ot">=</span> f s</span>
|
||
<span id="cb259-4"><a href="#cb259-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-5"><a href="#cb259-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- operation that overwrites the state (and produces ())</span></span>
|
||
<span id="cb259-6"><a href="#cb259-6" aria-hidden="true" tabindex="-1"></a><span class="ot">put ::</span> s <span class="ot">-></span> <span class="dt">State</span> s ()</span>
|
||
<span id="cb259-7"><a href="#cb259-7" aria-hidden="true" tabindex="-1"></a>put state <span class="ot">=</span> <span class="dt">State</span> (\oldState <span class="ot">-></span> ((),state))</span>
|
||
<span id="cb259-8"><a href="#cb259-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-9"><a href="#cb259-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- operation that produces the current state</span></span>
|
||
<span id="cb259-10"><a href="#cb259-10" aria-hidden="true" tabindex="-1"></a><span class="ot">get ::</span> <span class="dt">State</span> s s</span>
|
||
<span id="cb259-11"><a href="#cb259-11" aria-hidden="true" tabindex="-1"></a>get <span class="ot">=</span> <span class="dt">State</span> (\state <span class="ot">-></span> (state,state))</span>
|
||
<span id="cb259-12"><a href="#cb259-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-13"><a href="#cb259-13" aria-hidden="true" tabindex="-1"></a><span class="co">-- operation that modifies the current state with a function (and produces ())</span></span>
|
||
<span id="cb259-14"><a href="#cb259-14" aria-hidden="true" tabindex="-1"></a><span class="ot">modify ::</span> (s <span class="ot">-></span> s) <span class="ot">-></span> <span class="dt">State</span> s ()</span>
|
||
<span id="cb259-15"><a href="#cb259-15" aria-hidden="true" tabindex="-1"></a>modify f <span class="ot">=</span> <span class="dt">State</span> (\state <span class="ot">-></span> ((), f state))</span>
|
||
<span id="cb259-16"><a href="#cb259-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-17"><a href="#cb259-17" aria-hidden="true" tabindex="-1"></a><span class="co">-- Functor and Applicative instances skipped</span></span>
|
||
<span id="cb259-18"><a href="#cb259-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-19"><a href="#cb259-19" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> (<span class="dt">State</span> s) <span class="kw">where</span></span>
|
||
<span id="cb259-20"><a href="#cb259-20" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> x <span class="ot">=</span> <span class="dt">State</span> (\s <span class="ot">-></span> (x,s))</span>
|
||
<span id="cb259-21"><a href="#cb259-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb259-22"><a href="#cb259-22" aria-hidden="true" tabindex="-1"></a> op <span class="op">>>=</span> f <span class="ot">=</span> <span class="dt">State</span> h</span>
|
||
<span id="cb259-23"><a href="#cb259-23" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> h state0 <span class="ot">=</span> <span class="kw">let</span> (val,state1) <span class="ot">=</span> runState op state0</span>
|
||
<span id="cb259-24"><a href="#cb259-24" aria-hidden="true" tabindex="-1"></a> op2 <span class="ot">=</span> f val</span>
|
||
<span id="cb259-25"><a href="#cb259-25" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> runState op2 state1</span></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>
|
||
<div class="sourceCode" id="cb260"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb260-1"><a href="#cb260-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Monad</span> m <span class="kw">where</span></span>
|
||
<span id="cb260-2"><a href="#cb260-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> (>>=) ::</span> m a <span class="ot">-></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> m b</span>
|
||
<span id="cb260-3"><a href="#cb260-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb260-4"><a href="#cb260-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
|
||
<span id="cb260-5"><a href="#cb260-5" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb260-6"><a href="#cb260-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb260-7"><a href="#cb260-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> (<span class="dt">State</span> s) <span class="kw">where</span></span>
|
||
<span id="cb260-8"><a href="#cb260-8" aria-hidden="true" tabindex="-1"></a><span class="ot"> (>>=) ::</span> <span class="dt">State</span> s a <span class="ot">-></span> (a <span class="ot">-></span> <span class="dt">State</span> s b) <span class="ot">-></span> <span class="dt">State</span> s b</span></code></pre></div>
|
||
<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 simple counter.</p>
|
||
<div class="sourceCode" id="cb261"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb261-1"><a href="#cb261-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- adds i to the value of the counter</span></span>
|
||
<span id="cb261-2"><a href="#cb261-2" aria-hidden="true" tabindex="-1"></a><span class="ot">add ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">State</span> <span class="dt">Int</span> ()</span>
|
||
<span id="cb261-3"><a href="#cb261-3" aria-hidden="true" tabindex="-1"></a>add i <span class="ot">=</span> <span class="kw">do</span> old <span class="ot"><-</span> get</span>
|
||
<span id="cb261-4"><a href="#cb261-4" aria-hidden="true" tabindex="-1"></a> put (old<span class="op">+</span>i)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb262"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb262-1"><a href="#cb262-1" aria-hidden="true" tabindex="-1"></a>runState (add <span class="dv">1</span> <span class="op">>></span> add <span class="dv">3</span> <span class="op">>></span> add <span class="dv">5</span> <span class="op">>></span> add <span class="dv">6</span>) <span class="dv">0</span></span>
|
||
<span id="cb262-2"><a href="#cb262-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> ((),<span class="dv">15</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb263"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb263-1"><a href="#cb263-1" aria-hidden="true" tabindex="-1"></a><span class="ot">example ::</span> <span class="dt">State</span> <span class="dt">Int</span> <span class="dt">Int</span></span>
|
||
<span id="cb263-2"><a href="#cb263-2" aria-hidden="true" tabindex="-1"></a>example <span class="ot">=</span> <span class="kw">do</span> add <span class="dv">3</span> <span class="co">-- increment state by 3</span></span>
|
||
<span id="cb263-3"><a href="#cb263-3" aria-hidden="true" tabindex="-1"></a> value <span class="ot"><-</span> get <span class="co">-- value is current state, i.e. initial+3</span></span>
|
||
<span id="cb263-4"><a href="#cb263-4" aria-hidden="true" tabindex="-1"></a> add <span class="dv">1000</span> <span class="co">-- increment state by 1000</span></span>
|
||
<span id="cb263-5"><a href="#cb263-5" aria-hidden="true" tabindex="-1"></a> put (value <span class="op">+</span> <span class="dv">1</span>) <span class="co">-- overwrite state with value+1, i.e. initial+4</span></span>
|
||
<span id="cb263-6"><a href="#cb263-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> value <span class="co">-- produce value, i.e. intial+3</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb264"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb264-1"><a href="#cb264-1" aria-hidden="true" tabindex="-1"></a>runState example <span class="dv">1</span></span>
|
||
<span id="cb264-2"><a href="#cb264-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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></span></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="cb265"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb265-1"><a href="#cb265-1" aria-hidden="true" tabindex="-1"></a><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 ()</span>
|
||
<span id="cb265-2"><a href="#cb265-2" aria-hidden="true" tabindex="-1"></a>findLargest [] <span class="ot">=</span> <span class="fu">return</span> ()</span>
|
||
<span id="cb265-3"><a href="#cb265-3" aria-hidden="true" tabindex="-1"></a>findLargest (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb265-4"><a href="#cb265-4" aria-hidden="true" tabindex="-1"></a> modify (\y <span class="ot">-></span> <span class="fu">max</span> x y) <span class="co">-- update state with max of current value and previous largest value</span></span>
|
||
<span id="cb265-5"><a href="#cb265-5" aria-hidden="true" tabindex="-1"></a> findLargest xs <span class="co">-- process rest of list</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb266"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb266-1"><a href="#cb266-1" aria-hidden="true" tabindex="-1"></a>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="op">==></span> ((),<span class="dv">7</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb267"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb267-1"><a href="#cb267-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- store the given value in the state list</span></span>
|
||
<span id="cb267-2"><a href="#cb267-2" aria-hidden="true" tabindex="-1"></a><span class="ot">remember ::</span> a <span class="ot">-></span> <span class="dt">State</span> [a] ()</span>
|
||
<span id="cb267-3"><a href="#cb267-3" aria-hidden="true" tabindex="-1"></a>remember x <span class="ot">=</span> modify (x<span class="op">:</span>)</span>
|
||
<span id="cb267-4"><a href="#cb267-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb267-5"><a href="#cb267-5" aria-hidden="true" tabindex="-1"></a><span class="ot">valuesAfterZero ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> ((),[<span class="dt">Int</span>])</span>
|
||
<span id="cb267-6"><a href="#cb267-6" aria-hidden="true" tabindex="-1"></a>valuesAfterZero xs <span class="ot">=</span> runState (go xs) []</span>
|
||
<span id="cb267-7"><a href="#cb267-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span><span class="ot"> go ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">State</span> [<span class="dt">Int</span>] ()</span>
|
||
<span id="cb267-8"><a href="#cb267-8" aria-hidden="true" tabindex="-1"></a> go (<span class="dv">0</span><span class="op">:</span>y<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> remember y</span>
|
||
<span id="cb267-9"><a href="#cb267-9" aria-hidden="true" tabindex="-1"></a> go (y<span class="op">:</span>xs)</span>
|
||
<span id="cb267-10"><a href="#cb267-10" aria-hidden="true" tabindex="-1"></a> go (x<span class="op">:</span>xs) <span class="ot">=</span> go xs</span>
|
||
<span id="cb267-11"><a href="#cb267-11" aria-hidden="true" tabindex="-1"></a> go [] <span class="ot">=</span> <span class="fu">return</span> ()</span></code></pre></div>
|
||
<div class="sourceCode" id="cb268"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb268-1"><a href="#cb268-1" aria-hidden="true" tabindex="-1"></a>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>]</span>
|
||
<span id="cb268-2"><a href="#cb268-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>])</span></code></pre></div>
|
||
<p><strong>Note!</strong> By the way, the actual implementation of the
|
||
<code>State</code> monad doesn’t have a <code>State</code> constructor
|
||
like our simplified exmaple. If you want to wrap a function into a
|
||
<code>State</code> operation, use this helper instead:</p>
|
||
<pre><code>state :: (s -> (a, s)) -> State s a</code></pre>
|
||
<h2 data-number="13.9" 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="cb270"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb270-1"><a href="#cb270-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb270-2"><a href="#cb270-2" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb270-3"><a href="#cb270-3" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb270-4"><a href="#cb270-4" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb270-5"><a href="#cb270-5" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span><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></span>
|
||
<span id="cb270-6"><a href="#cb270-6" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM_</span><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></span>
|
||
<span id="cb270-7"><a href="#cb270-7" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb270-8"><a href="#cb270-8" aria-hidden="true" tabindex="-1"></a><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></span></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="cb271"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb271-1"><a href="#cb271-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span> (\x <span class="ot">-></span> <span class="kw">if</span> (x<span class="op">></span><span class="dv">0</span>) <span class="kw">then</span> <span class="dt">Just</span> (x<span class="op">-</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="op">==></span> <span class="dt">Just</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb271-2"><a href="#cb271-2" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span> (\x <span class="ot">-></span> <span class="kw">if</span> (x<span class="op">></span><span class="dv">0</span>) <span class="kw">then</span> <span class="dt">Just</span> (x<span class="op">-</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="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb271-3"><a href="#cb271-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb271-4"><a href="#cb271-4" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span> (\x <span class="ot">-></span> msg <span class="st">"increment"</span> <span class="op">>></span> msg (<span class="fu">show</span> x) <span class="op">>></span> <span class="fu">return</span> (x<span class="op">+</span><span class="dv">1</span>)) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb271-5"><a href="#cb271-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]</span>
|
||
<span id="cb271-6"><a href="#cb271-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb271-7"><a href="#cb271-7" aria-hidden="true" tabindex="-1"></a>runState (<span class="fu">mapM</span> (\x <span class="ot">-></span> modify (x<span class="op">+</span>) <span class="op">>></span> <span class="fu">return</span> (x<span class="op">+</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></span>
|
||
<span id="cb271-8"><a href="#cb271-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> ([<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>],<span class="dv">6</span>)</span></code></pre></div>
|
||
<p>Some more examples:</p>
|
||
<div class="sourceCode" id="cb272"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb272-1"><a href="#cb272-1" aria-hidden="true" tabindex="-1"></a><span class="ot">safeHead ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb272-2"><a href="#cb272-2" aria-hidden="true" tabindex="-1"></a>safeHead [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb272-3"><a href="#cb272-3" aria-hidden="true" tabindex="-1"></a>safeHead (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb272-4"><a href="#cb272-4" aria-hidden="true" tabindex="-1"></a><span class="ot">firsts ::</span> [[a]] <span class="ot">-></span> <span class="dt">Maybe</span> [a]</span>
|
||
<span id="cb272-5"><a href="#cb272-5" aria-hidden="true" tabindex="-1"></a>firsts xs <span class="ot">=</span> forM xs safeHead</span></code></pre></div>
|
||
<div class="sourceCode" id="cb273"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb273-1"><a href="#cb273-1" aria-hidden="true" tabindex="-1"></a>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="op">==></span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span>
|
||
<span id="cb273-2"><a href="#cb273-2" aria-hidden="true" tabindex="-1"></a>firsts [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[],[<span class="dv">6</span>]] <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb274"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb274-1"><a href="#cb274-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- an abbreviated version of an example from the last section</span></span>
|
||
<span id="cb274-2"><a href="#cb274-2" aria-hidden="true" tabindex="-1"></a><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 ()</span>
|
||
<span id="cb274-3"><a href="#cb274-3" aria-hidden="true" tabindex="-1"></a>findLargest xs <span class="ot">=</span> <span class="fu">mapM_</span> update xs</span>
|
||
<span id="cb274-4"><a href="#cb274-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> update x <span class="ot">=</span> modify (\y <span class="ot">-></span> <span class="fu">max</span> x y)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb275"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb275-1"><a href="#cb275-1" aria-hidden="true" tabindex="-1"></a>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="op">==></span> ((),<span class="dv">7</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb276"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb276-1"><a href="#cb276-1" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> increment <span class="ot">=</span> modify (<span class="op">+</span><span class="dv">1</span>) <span class="op">>></span> get</span>
|
||
<span id="cb276-2"><a href="#cb276-2" aria-hidden="true" tabindex="-1"></a> ops <span class="ot">=</span> replicateM <span class="dv">4</span> increment</span>
|
||
<span id="cb276-3"><a href="#cb276-3" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> runState ops <span class="dv">0</span></span>
|
||
<span id="cb276-4"><a href="#cb276-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)</span></code></pre></div>
|
||
<p>Here’s <code>filter</code> reimplemented using the <code>State</code>
|
||
monad:</p>
|
||
<div class="sourceCode" id="cb277"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb277-1"><a href="#cb277-1" aria-hidden="true" tabindex="-1"></a><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] ()</span>
|
||
<span id="cb277-2"><a href="#cb277-2" aria-hidden="true" tabindex="-1"></a>rememberElements f xs <span class="ot">=</span> <span class="fu">mapM_</span> maybePut xs</span>
|
||
<span id="cb277-3"><a href="#cb277-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> maybePut x <span class="ot">=</span> when (f x) (modify (<span class="op">++</span>[x]))</span>
|
||
<span id="cb277-4"><a href="#cb277-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb277-5"><a href="#cb277-5" aria-hidden="true" tabindex="-1"></a><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]</span>
|
||
<span id="cb277-6"><a href="#cb277-6" aria-hidden="true" tabindex="-1"></a>sfilter f xs <span class="ot">=</span> finalState</span>
|
||
<span id="cb277-7"><a href="#cb277-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> (_, finalState) <span class="ot">=</span> runState (rememberElements f xs) []</span></code></pre></div>
|
||
<div class="sourceCode" id="cb278"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb278-1"><a href="#cb278-1" aria-hidden="true" tabindex="-1"></a>sfilter <span class="fu">even</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>
|
||
<span id="cb278-2"><a href="#cb278-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">2</span>,<span class="dv">4</span>]</span></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="cb279"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb279-1"><a href="#cb279-1" aria-hidden="true" tabindex="-1"></a>mywhen b op <span class="ot">=</span> <span class="kw">if</span> b <span class="kw">then</span> op <span class="kw">else</span> <span class="fu">return</span> ()</span>
|
||
<span id="cb279-2"><a href="#cb279-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb279-3"><a href="#cb279-3" aria-hidden="true" tabindex="-1"></a>mymapM_ op [] <span class="ot">=</span> <span class="fu">return</span> ()</span>
|
||
<span id="cb279-4"><a href="#cb279-4" aria-hidden="true" tabindex="-1"></a>mymapM_ op (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> op x</span>
|
||
<span id="cb279-5"><a href="#cb279-5" aria-hidden="true" tabindex="-1"></a> mymapM_ op xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb280"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb280-1"><a href="#cb280-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> <span class="op">:</span>t mywhen</span>
|
||
<span id="cb280-2"><a href="#cb280-2" aria-hidden="true" tabindex="-1"></a><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 ()</span>
|
||
<span id="cb280-3"><a href="#cb280-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> <span class="op">:</span>t mymapM_</span>
|
||
<span id="cb280-4"><a href="#cb280-4" aria-hidden="true" tabindex="-1"></a><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 ()</span></code></pre></div>
|
||
<p>We can use these generic operations in each of our example
|
||
monads:</p>
|
||
<div class="sourceCode" id="cb281"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb281-1"><a href="#cb281-1" aria-hidden="true" tabindex="-1"></a><span class="ot">perhapsDecrease ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb281-2"><a href="#cb281-2" aria-hidden="true" tabindex="-1"></a>perhapsDecrease x <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb281-3"><a href="#cb281-3" aria-hidden="true" tabindex="-1"></a> mywhen (x<span class="op"><=</span><span class="dv">0</span>) <span class="dt">Nothing</span></span>
|
||
<span id="cb281-4"><a href="#cb281-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (x<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb282"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb282-1"><a href="#cb282-1" aria-hidden="true" tabindex="-1"></a>perhapsDecrease <span class="dv">2</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">1</span></span>
|
||
<span id="cb282-2"><a href="#cb282-2" aria-hidden="true" tabindex="-1"></a>perhapsDecrease <span class="dv">0</span> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb283"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb283-1"><a href="#cb283-1" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb283-2"><a href="#cb283-2" aria-hidden="true" tabindex="-1"></a>search x ys <span class="ot">=</span> mymapM_ look ys</span>
|
||
<span id="cb283-3"><a href="#cb283-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> look y <span class="ot">=</span> mywhen (x<span class="op">==</span>y) (msg (<span class="st">"Found "</span><span class="op">++</span><span class="fu">show</span> y))</span></code></pre></div>
|
||
<div class="sourceCode" id="cb284"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb284-1"><a href="#cb284-1" aria-hidden="true" tabindex="-1"></a>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="op">==></span> <span class="dt">Logger</span> [<span class="st">"Found 3"</span>,<span class="st">"Found 3"</span>] ()</span></code></pre></div>
|
||
<div class="sourceCode" id="cb285"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb285-1"><a href="#cb285-1" aria-hidden="true" tabindex="-1"></a><span class="ot">sumPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">State</span> <span class="dt">Int</span> ()</span>
|
||
<span id="cb285-2"><a href="#cb285-2" aria-hidden="true" tabindex="-1"></a>sumPositive xs <span class="ot">=</span> mymapM_ f xs</span>
|
||
<span id="cb285-3"><a href="#cb285-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> f x <span class="ot">=</span> when (x<span class="op">></span><span class="dv">0</span>) (modify (x<span class="op">+</span>))</span></code></pre></div>
|
||
<div class="sourceCode" id="cb286"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb286-1"><a href="#cb286-1" aria-hidden="true" tabindex="-1"></a>runState (sumPositive [<span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">2</span>,<span class="dv">3</span>]) <span class="dv">0</span> <span class="op">==></span> ((),<span class="dv">6</span>)</span></code></pre></div>
|
||
<h2 data-number="13.10" 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="cb287"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb287-1"><a href="#cb287-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb287-2"><a href="#cb287-2" aria-hidden="true" tabindex="-1"></a>liftM f op <span class="ot">=</span> <span class="kw">do</span> x <span class="ot"><-</span> op</span>
|
||
<span id="cb287-3"><a href="#cb287-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (f x)</span></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="cb288"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb288-1"><a href="#cb288-1" aria-hidden="true" tabindex="-1"></a>liftM <span class="fu">negate</span> (<span class="dt">Just</span> <span class="dv">3</span>)</span>
|
||
<span id="cb288-2"><a href="#cb288-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> (<span class="op">-</span><span class="dv">3</span>)</span>
|
||
<span id="cb288-3"><a href="#cb288-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb288-4"><a href="#cb288-4" aria-hidden="true" tabindex="-1"></a>liftM <span class="fu">sort</span> <span class="op">$</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>]]</span>
|
||
<span id="cb288-5"><a href="#cb288-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb288-6"><a href="#cb288-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb288-7"><a href="#cb288-7" aria-hidden="true" tabindex="-1"></a>runState (liftM <span class="fu">negate</span> get) <span class="dv">3</span></span>
|
||
<span id="cb288-8"><a href="#cb288-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="op">-</span><span class="dv">3</span>,<span class="dv">3</span>)</span></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="cb289"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb289-1"><a href="#cb289-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span><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</span></code></pre></div>
|
||
<div class="sourceCode" id="cb290"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb290-1"><a href="#cb290-1" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> <span class="fu">negate</span> (<span class="dt">Just</span> <span class="dv">3</span>)</span>
|
||
<span id="cb290-2"><a href="#cb290-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> (<span class="op">-</span><span class="dv">3</span>)</span>
|
||
<span id="cb290-3"><a href="#cb290-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb290-4"><a href="#cb290-4" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> <span class="fu">sort</span> <span class="op">$</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>]]</span>
|
||
<span id="cb290-5"><a href="#cb290-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb290-6"><a href="#cb290-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb290-7"><a href="#cb290-7" aria-hidden="true" tabindex="-1"></a>runState (<span class="fu">fmap</span> <span class="fu">negate</span> get) <span class="dv">3</span></span>
|
||
<span id="cb290-8"><a href="#cb290-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (<span class="op">-</span><span class="dv">3</span>,<span class="dv">3</span>)</span></code></pre></div>
|
||
<h2 data-number="13.11" 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="cb291"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb291-1"><a href="#cb291-1" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">>>=</span> \x <span class="ot">-></span> [<span class="op">-</span>x,x]</span>
|
||
<span id="cb291-2"><a href="#cb291-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="op">-</span><span class="dv">1</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="dv">2</span>,<span class="op">-</span><span class="dv">3</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p>We can filter out unsuitable values by produing an empty list:</p>
|
||
<div class="sourceCode" id="cb292"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb292-1"><a href="#cb292-1" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">>>=</span> \x <span class="ot">-></span> <span class="kw">if</span> x<span class="op">></span><span class="dv">1</span> <span class="kw">then</span> [x] <span class="kw">else</span> []</span>
|
||
<span id="cb292-2"><a href="#cb292-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">2</span>,<span class="dv">3</span>]</span></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="cb293"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb293-1"><a href="#cb293-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> word <span class="ot"><-</span> [<span class="st">"Blue"</span>, <span class="st">"Green"</span>]</span>
|
||
<span id="cb293-2"><a href="#cb293-2" aria-hidden="true" tabindex="-1"></a> number <span class="ot"><-</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb293-3"><a href="#cb293-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (word <span class="op">++</span> <span class="fu">show</span> number)</span>
|
||
<span id="cb293-4"><a href="#cb293-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]</span></code></pre></div>
|
||
<p>More interesting example: find all the pairs in a list that sum to
|
||
<code>k</code>. (The same element twice counts as a pair.)</p>
|
||
<div class="sourceCode" id="cb294"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb294-1"><a href="#cb294-1" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb294-2"><a href="#cb294-2" aria-hidden="true" tabindex="-1"></a>findSum xs k <span class="ot">=</span> <span class="kw">do</span> a <span class="ot"><-</span> xs</span>
|
||
<span id="cb294-3"><a href="#cb294-3" aria-hidden="true" tabindex="-1"></a> b <span class="ot"><-</span> xs</span>
|
||
<span id="cb294-4"><a href="#cb294-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> (a<span class="op">+</span>b<span class="op">==</span>k) <span class="kw">then</span> [(a,b)] <span class="kw">else</span> []</span></code></pre></div>
|
||
<div class="sourceCode" id="cb295"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb295-1"><a href="#cb295-1" aria-hidden="true" tabindex="-1"></a>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></span>
|
||
<span id="cb295-2"><a href="#cb295-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>)]</span></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="cb296"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb296-1"><a href="#cb296-1" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Data.List</span> (sortBy)</span>
|
||
<span id="cb296-2"><a href="#cb296-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb296-3"><a href="#cb296-3" aria-hidden="true" tabindex="-1"></a><span class="ot">substrings ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</span>
|
||
<span id="cb296-4"><a href="#cb296-4" aria-hidden="true" tabindex="-1"></a>substrings xs <span class="ot">=</span> <span class="kw">do</span> start <span class="ot"><-</span> [<span class="dv">0</span><span class="op">..</span><span class="fu">length</span> xs <span class="op">-</span> <span class="dv">1</span>]</span>
|
||
<span id="cb296-5"><a href="#cb296-5" aria-hidden="true" tabindex="-1"></a> end <span class="ot"><-</span> [start<span class="op">+</span><span class="dv">1</span><span class="op">..</span><span class="fu">length</span> xs <span class="op">-</span> <span class="dv">1</span>]</span>
|
||
<span id="cb296-6"><a href="#cb296-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> <span class="op">$</span> <span class="fu">drop</span> start <span class="op">$</span> <span class="fu">take</span> end <span class="op">$</span> xs</span>
|
||
<span id="cb296-7"><a href="#cb296-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb296-8"><a href="#cb296-8" aria-hidden="true" tabindex="-1"></a><span class="ot">palindromesIn ::</span> <span class="dt">String</span> <span class="ot">-></span> [<span class="dt">String</span>]</span>
|
||
<span id="cb296-9"><a href="#cb296-9" aria-hidden="true" tabindex="-1"></a>palindromesIn xs <span class="ot">=</span> <span class="kw">do</span> s <span class="ot"><-</span> substrings xs</span>
|
||
<span id="cb296-10"><a href="#cb296-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> (s<span class="op">==</span><span class="fu">reverse</span> s) <span class="kw">then</span> <span class="fu">return</span> s <span class="kw">else</span> []</span>
|
||
<span id="cb296-11"><a href="#cb296-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb296-12"><a href="#cb296-12" aria-hidden="true" tabindex="-1"></a>longestPalindrome xs <span class="ot">=</span> <span class="fu">head</span> <span class="op">.</span> sortBy f <span class="op">$</span> palindromesIn xs</span>
|
||
<span id="cb296-13"><a href="#cb296-13" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> f s s' <span class="ot">=</span> <span class="fu">compare</span> (<span class="fu">length</span> s') (<span class="fu">length</span> s) <span class="co">-- longer is smaller</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb297"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb297-1"><a href="#cb297-1" aria-hidden="true" tabindex="-1"></a>palindromesIn <span class="st">"aabbacddcaca"</span></span>
|
||
<span id="cb297-2"><a href="#cb297-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></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>]</span>
|
||
<span id="cb297-3"><a href="#cb297-3" aria-hidden="true" tabindex="-1"></a>longestPalindrome <span class="st">"aabbacddcaca"</span></span>
|
||
<span id="cb297-4"><a href="#cb297-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="st">"acddca"</span></span></code></pre></div>
|
||
<p>Here’s the surprisingly simple implementation of the list monad:</p>
|
||
<div class="sourceCode" id="cb298"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb298-1"><a href="#cb298-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monad</span> [] <span class="kw">where</span></span>
|
||
<span id="cb298-2"><a href="#cb298-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> x <span class="ot">=</span> [x] <span class="co">-- an operation that produces one value</span></span>
|
||
<span id="cb298-3"><a href="#cb298-3" aria-hidden="true" tabindex="-1"></a> lis <span class="op">>>=</span> f <span class="ot">=</span> <span class="fu">concat</span> (<span class="fu">map</span> f lis) <span class="co">-- compute f for all values, combine the results</span></span></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="cb299"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb299-1"><a href="#cb299-1" aria-hidden="true" tabindex="-1"></a><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>)]</span>
|
||
<span id="cb299-2"><a href="#cb299-2" aria-hidden="true" tabindex="-1"></a>findSum xs k <span class="ot">=</span> [(a,b) <span class="op">|</span> a <span class="ot"><-</span> xs, b <span class="ot"><-</span> xs, a<span class="op">+</span>b<span class="op">==</span>k ]</span></code></pre></div>
|
||
<h2 data-number="13.12" 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="cb300"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb300-1"><a href="#cb300-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printTwoThings ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb300-2"><a href="#cb300-2" aria-hidden="true" tabindex="-1"></a>printTwoThings <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"One!"</span> <span class="op">>></span> <span class="fu">print</span> <span class="dv">2</span></span>
|
||
<span id="cb300-3"><a href="#cb300-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb300-4"><a href="#cb300-4" aria-hidden="true" tabindex="-1"></a><span class="ot">echo ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb300-5"><a href="#cb300-5" aria-hidden="true" tabindex="-1"></a>echo <span class="ot">=</span> <span class="fu">getLine</span> <span class="op">>>=</span> <span class="fu">putStrLn</span></span>
|
||
<span id="cb300-6"><a href="#cb300-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb300-7"><a href="#cb300-7" aria-hidden="true" tabindex="-1"></a><span class="ot">verboseEcho ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb300-8"><a href="#cb300-8" aria-hidden="true" tabindex="-1"></a>verboseEcho <span class="ot">=</span> <span class="fu">getLine</span> <span class="op">>>=</span> \s <span class="ot">-></span> <span class="fu">putStrLn</span> (<span class="st">"You wrote: "</span> <span class="op">++</span> s)</span>
|
||
<span id="cb300-9"><a href="#cb300-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb300-10"><a href="#cb300-10" aria-hidden="true" tabindex="-1"></a><span class="ot">query ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">String</span></span>
|
||
<span id="cb300-11"><a href="#cb300-11" aria-hidden="true" tabindex="-1"></a>query question <span class="ot">=</span> <span class="fu">putStrLn</span> question <span class="op">>></span> <span class="fu">getLine</span></span>
|
||
<span id="cb300-12"><a href="#cb300-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb300-13"><a href="#cb300-13" aria-hidden="true" tabindex="-1"></a><span class="ot">confirm ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Bool</span></span>
|
||
<span id="cb300-14"><a href="#cb300-14" aria-hidden="true" tabindex="-1"></a>confirm question <span class="ot">=</span> <span class="fu">putStrLn</span> question <span class="op">>></span> <span class="fu">fmap</span> interpret <span class="fu">getLine</span></span>
|
||
<span id="cb300-15"><a href="#cb300-15" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> interpret <span class="st">"Y"</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb300-16"><a href="#cb300-16" aria-hidden="true" tabindex="-1"></a> interpret _ <span class="ot">=</span> <span class="dt">False</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb301"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb301-1"><a href="#cb301-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printTwoThings</span>
|
||
<span id="cb301-2"><a href="#cb301-2" aria-hidden="true" tabindex="-1"></a><span class="dt">One</span><span class="op">!</span></span>
|
||
<span id="cb301-3"><a href="#cb301-3" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
|
||
<span id="cb301-4"><a href="#cb301-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb301-5"><a href="#cb301-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> verboseEcho</span>
|
||
<span id="cb301-6"><a href="#cb301-6" aria-hidden="true" tabindex="-1"></a><span class="dt">The</span> <span class="dt">Iliad</span></span>
|
||
<span id="cb301-7"><a href="#cb301-7" aria-hidden="true" tabindex="-1"></a><span class="dt">You</span> wrote<span class="op">:</span> <span class="dt">The</span> <span class="dt">Iliad</span></span>
|
||
<span id="cb301-8"><a href="#cb301-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb301-9"><a href="#cb301-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> answer <span class="ot"><-</span> query <span class="st">"Why am I here?"</span></span>
|
||
<span id="cb301-10"><a href="#cb301-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Why</span> am <span class="dt">I</span> here<span class="op">?</span></span>
|
||
<span id="cb301-11"><a href="#cb301-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Good</span> question<span class="op">!</span></span>
|
||
<span id="cb301-12"><a href="#cb301-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> answer</span>
|
||
<span id="cb301-13"><a href="#cb301-13" aria-hidden="true" tabindex="-1"></a><span class="st">"Good question!"</span></span>
|
||
<span id="cb301-14"><a href="#cb301-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb301-15"><a href="#cb301-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> b <span class="ot"><-</span> confirm <span class="st">"Fire warheads?"</span></span>
|
||
<span id="cb301-16"><a href="#cb301-16" aria-hidden="true" tabindex="-1"></a><span class="dt">Fire</span> warheads<span class="op">?</span></span>
|
||
<span id="cb301-17"><a href="#cb301-17" aria-hidden="true" tabindex="-1"></a>no no no no</span>
|
||
<span id="cb301-18"><a href="#cb301-18" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> b</span>
|
||
<span id="cb301-19"><a href="#cb301-19" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb301-20"><a href="#cb301-20" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> b <span class="ot"><-</span> confirm <span class="st">"Make love, not war?"</span></span>
|
||
<span id="cb301-21"><a href="#cb301-21" aria-hidden="true" tabindex="-1"></a><span class="dt">Make</span> love, <span class="fu">not</span> war<span class="op">?</span></span>
|
||
<span id="cb301-22"><a href="#cb301-22" aria-hidden="true" tabindex="-1"></a><span class="dt">Y</span></span>
|
||
<span id="cb301-23"><a href="#cb301-23" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> b</span>
|
||
<span id="cb301-24"><a href="#cb301-24" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<h2 data-number="13.13" 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 data-number="13.13.1" 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 data-number="13.13.2" 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="cb302"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb302-1"><a href="#cb302-1" aria-hidden="true" tabindex="-1"></a>Stream<span class="op"><</span><span class="bu">Integer</span><span class="op">></span> <span class="fu">parseNumbers</span><span class="op">(</span>Stream<span class="op"><</span><span class="bu">String</span><span class="op">></span> lines<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb302-2"><a href="#cb302-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> lines<span class="op">.</span><span class="fu">flatMap</span><span class="op">(</span>words<span class="op">).</span><span class="fu">map</span><span class="op">(</span>read<span class="op">);</span></span>
|
||
<span id="cb302-3"><a href="#cb302-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>This corresponds to the following Haskell list monad code:</p>
|
||
<div class="sourceCode" id="cb303"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb303-1"><a href="#cb303-1" aria-hidden="true" tabindex="-1"></a><span class="ot">parseNumbers ::</span> [<span class="dt">String</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb303-2"><a href="#cb303-2" aria-hidden="true" tabindex="-1"></a>parseNumbers strings <span class="ot">=</span> <span class="fu">fmap</span> <span class="fu">read</span> (strings <span class="op">>>=</span> <span class="fu">words</span>)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb304"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb304-1"><a href="#cb304-1" aria-hidden="true" tabindex="-1"></a>parseNumbers [<span class="st">"123 456"</span>,<span class="st">"7 89"</span>] <span class="op">==></span> [<span class="dv">123</span>,<span class="dv">456</span>,<span class="dv">7</span>,<span class="dv">89</span>]</span></code></pre></div>
|
||
<h3 data-number="13.13.3" 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="cb305"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb305-1"><a href="#cb305-1" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span> <span class="fu">concatPromises</span>(promise1<span class="op">,</span> promise2) {</span>
|
||
<span id="cb305-2"><a href="#cb305-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> promise1<span class="op">.</span><span class="fu">then</span>(value1 <span class="kw">=></span> promise2<span class="op">.</span><span class="fu">then</span>(value2 <span class="kw">=></span> value1<span class="op">+</span>value2))<span class="op">;</span></span>
|
||
<span id="cb305-3"><a href="#cb305-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||
<div class="sourceCode" id="cb306"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb306-1"><a href="#cb306-1" aria-hidden="true" tabindex="-1"></a><span class="op">>></span> <span class="fu">concatPromises</span>(<span class="bu">Promise</span><span class="op">.</span><span class="fu">resolve</span>(<span class="st">"abc"</span>)<span class="op">,</span> <span class="bu">Promise</span><span class="op">.</span><span class="fu">resolve</span>(<span class="st">"def"</span>))<span class="op">.</span><span class="fu">then</span>(<span class="bu">console</span><span class="op">.</span><span class="fu">log</span>)</span>
|
||
<span id="cb306-2"><a href="#cb306-2" aria-hidden="true" tabindex="-1"></a>abcdef</span></code></pre></div>
|
||
<div class="sourceCode" id="cb307"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb307-1"><a href="#cb307-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb307-2"><a href="#cb307-2" aria-hidden="true" tabindex="-1"></a>concatMonadic op1 op2 <span class="ot">=</span> op1 <span class="op">>>=</span> (\value1 <span class="ot">-></span> op2 <span class="op">>>=</span> (\value2 <span class="ot">-></span> <span class="fu">return</span> (value1<span class="op">++</span>value2)))</span></code></pre></div>
|
||
<div class="sourceCode" id="cb308"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb308-1"><a href="#cb308-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> concatMonadic (<span class="dt">Just</span> <span class="st">"abc"</span>) (<span class="dt">Just</span> <span class="st">"def"</span>)</span>
|
||
<span id="cb308-2"><a href="#cb308-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"abcdef"</span></span></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="cb309"><pre
|
||
class="sourceCode javascript"><code class="sourceCode javascript"><span id="cb309-1"><a href="#cb309-1" aria-hidden="true" tabindex="-1"></a><span class="kw">async</span> <span class="kw">function</span> <span class="fu">concatPromises</span>(promise1<span class="op">,</span> promise2) {</span>
|
||
<span id="cb309-2"><a href="#cb309-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> value1 <span class="op">=</span> <span class="cf">await</span> promise1<span class="op">;</span></span>
|
||
<span id="cb309-3"><a href="#cb309-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> value2 <span class="op">=</span> <span class="cf">await</span> promise2<span class="op">;</span></span>
|
||
<span id="cb309-4"><a href="#cb309-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> value1<span class="op">+</span>value2<span class="op">;</span></span>
|
||
<span id="cb309-5"><a href="#cb309-5" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
||
<div class="sourceCode" id="cb310"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb310-1"><a href="#cb310-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb310-2"><a href="#cb310-2" aria-hidden="true" tabindex="-1"></a>concatMonadic op1 op2 <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb310-3"><a href="#cb310-3" aria-hidden="true" tabindex="-1"></a> value1 <span class="ot"><-</span> op1</span>
|
||
<span id="cb310-4"><a href="#cb310-4" aria-hidden="true" tabindex="-1"></a> value2 <span class="ot"><-</span> op2</span>
|
||
<span id="cb310-5"><a href="#cb310-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (value1<span class="op">++</span>value2)</span></code></pre></div>
|
||
<h2 data-number="13.14" 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 data-number="13.15" 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 data-number="13.16" 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="cb311"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb311-1"><a href="#cb311-1" aria-hidden="true" tabindex="-1"></a><span class="kw">do</span> y <span class="ot"><-</span> z</span>
|
||
<span id="cb311-2"><a href="#cb311-2" aria-hidden="true" tabindex="-1"></a> s y</span>
|
||
<span id="cb311-3"><a href="#cb311-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (f y)</span></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 data-number="13.17" 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>
|
||
</ul>
|
||
<h1 data-number="14" 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>
|
||
<p><strong>Note!</strong> When reading the documentation for the
|
||
libraries, remember to pay attention to the library version. You can see
|
||
the versions used on the course in the <a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/tests.cabal"><code>tests.cabal</code>
|
||
file</a>. The links in the course material always take you to the right
|
||
version, as does the <code>stack haddock --open <package></code>
|
||
command. See also <a
|
||
href="https://haskell.mooc.fi/part1#reading-docs">Reading Docs in Part
|
||
1</a>.</p>
|
||
<h2 data-number="14.1" 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.5.0/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 data-number="14.1.1" 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.5.0/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="cb312"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb312-1"><a href="#cb312-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></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></span>
|
||
<span id="cb312-2"><a href="#cb312-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> <span class="op">:</span>t T.pack</span>
|
||
<span id="cb312-3"><a href="#cb312-3" aria-hidden="true" tabindex="-1"></a>T.pack<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">T.Text</span></span>
|
||
<span id="cb312-4"><a href="#cb312-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> phrase <span class="ot">=</span> T.pack <span class="st">"brevity is the soul of wit"</span></span>
|
||
<span id="cb312-5"><a href="#cb312-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> <span class="op">:</span>t phrase</span>
|
||
<span id="cb312-6"><a href="#cb312-6" aria-hidden="true" tabindex="-1"></a><span class="ot">phrase ::</span> <span class="dt">T.Text</span></span>
|
||
<span id="cb312-7"><a href="#cb312-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> phrase</span>
|
||
<span id="cb312-8"><a href="#cb312-8" aria-hidden="true" tabindex="-1"></a><span class="st">"brevity is the soul of wit"</span></span></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="cb313"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb313-1"><a href="#cb313-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> <span class="op">:</span>t T.length</span>
|
||
<span id="cb313-2"><a href="#cb313-2" aria-hidden="true" tabindex="-1"></a>T.length<span class="ot"> ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb313-3"><a href="#cb313-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.length phrase</span>
|
||
<span id="cb313-4"><a href="#cb313-4" aria-hidden="true" tabindex="-1"></a><span class="dv">26</span></span>
|
||
<span id="cb313-5"><a href="#cb313-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.head phrase</span>
|
||
<span id="cb313-6"><a href="#cb313-6" aria-hidden="true" tabindex="-1"></a><span class="ch">'b'</span></span>
|
||
<span id="cb313-7"><a href="#cb313-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.take <span class="dv">4</span> phrase</span>
|
||
<span id="cb313-8"><a href="#cb313-8" aria-hidden="true" tabindex="-1"></a><span class="st">"brev"</span></span>
|
||
<span id="cb313-9"><a href="#cb313-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> <span class="op">:</span>t T.words</span>
|
||
<span id="cb313-10"><a href="#cb313-10" aria-hidden="true" tabindex="-1"></a>T.words<span class="ot"> ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> [<span class="dt">T.Text</span>]</span>
|
||
<span id="cb313-11"><a href="#cb313-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.words phrase</span>
|
||
<span id="cb313-12"><a href="#cb313-12" aria-hidden="true" tabindex="-1"></a>[<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>]</span>
|
||
<span id="cb313-13"><a href="#cb313-13" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> <span class="op">:</span>t T.map</span>
|
||
<span id="cb313-14"><a href="#cb313-14" aria-hidden="true" tabindex="-1"></a>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></span>
|
||
<span id="cb313-15"><a href="#cb313-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.map (\c <span class="ot">-></span> <span class="kw">if</span> c<span class="op">==</span><span class="ch">'o'</span> <span class="kw">then</span> <span class="ch">'0'</span> <span class="kw">else</span> c) phrase</span>
|
||
<span id="cb313-16"><a href="#cb313-16" aria-hidden="true" tabindex="-1"></a><span class="st">"brevity is the s0ul 0f wit"</span></span></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="cb314"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb314-1"><a href="#cb314-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> phrase <span class="op"><></span> phrase</span>
|
||
<span id="cb314-2"><a href="#cb314-2" aria-hidden="true" tabindex="-1"></a><span class="st">"brevity is the soul of witbrevity is the soul of wit"</span></span>
|
||
<span id="cb314-3"><a href="#cb314-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.append phrase phrase</span>
|
||
<span id="cb314-4"><a href="#cb314-4" aria-hidden="true" tabindex="-1"></a><span class="st">"brevity is the soul of witbrevity is the soul of wit"</span></span>
|
||
<span id="cb314-5"><a href="#cb314-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.concat [phrase,phrase,phrase]</span>
|
||
<span id="cb314-6"><a href="#cb314-6" aria-hidden="true" tabindex="-1"></a><span class="st">"brevity is the soul of witbrevity is the soul of witbrevity is the soul of wit"</span></span></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="cb315"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb315-1"><a href="#cb315-1" aria-hidden="true" tabindex="-1"></a><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></span>
|
||
<span id="cb315-2"><a href="#cb315-2" aria-hidden="true" tabindex="-1"></a>countLetter c t <span class="ot">=</span></span>
|
||
<span id="cb315-3"><a href="#cb315-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> T.uncons t <span class="kw">of</span></span>
|
||
<span id="cb315-4"><a href="#cb315-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="dv">0</span></span>
|
||
<span id="cb315-5"><a href="#cb315-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> (x,rest) <span class="ot">-></span> (<span class="kw">if</span> x <span class="op">==</span> c <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span>) <span class="op">+</span> countLetter c rest</span></code></pre></div>
|
||
<div class="sourceCode" id="cb316"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb316-1"><a href="#cb316-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> countLetter <span class="ch">'t'</span> phrase</span>
|
||
<span id="cb316-2"><a href="#cb316-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></code></pre></div>
|
||
<h4 data-number="14.1.1.1" 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="cb317"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb317-1"><a href="#cb317-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></span> T.head (T.pack (<span class="fu">repeat</span> <span class="ch">'x'</span>))</span>
|
||
<span id="cb317-2"><a href="#cb317-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- never returns</span></span>
|
||
<span id="cb317-3"><a href="#cb317-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></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">TL</span></span>
|
||
<span id="cb317-4"><a href="#cb317-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> TL.head (TL.pack (<span class="fu">repeat</span> <span class="ch">'x'</span>))</span>
|
||
<span id="cb317-5"><a href="#cb317-5" aria-hidden="true" tabindex="-1"></a><span class="ch">'x'</span></span></code></pre></div>
|
||
<p>Another practical problem 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="cb318"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb318-1"><a href="#cb318-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> lazyPhrase <span class="ot">=</span> TL.pack <span class="st">"brevity is the soul of wit"</span></span>
|
||
<span id="cb318-2"><a href="#cb318-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> <span class="op">:</span>t lazyPhrase</span>
|
||
<span id="cb318-3"><a href="#cb318-3" aria-hidden="true" tabindex="-1"></a><span class="ot">lazyPhrase ::</span> <span class="dt">TL.Text</span></span>
|
||
<span id="cb318-4"><a href="#cb318-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> <span class="op">:</span>t phrase</span>
|
||
<span id="cb318-5"><a href="#cb318-5" aria-hidden="true" tabindex="-1"></a><span class="ot">phrase ::</span> <span class="dt">T.Text</span></span>
|
||
<span id="cb318-6"><a href="#cb318-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> lazyPhrase <span class="op">==</span> phrase</span>
|
||
<span id="cb318-7"><a href="#cb318-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb318-8"><a href="#cb318-8" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb318-9"><a href="#cb318-9" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘<span class="dt">TL.Text</span>’</span>
|
||
<span id="cb318-10"><a href="#cb318-10" aria-hidden="true" tabindex="-1"></a> with actual <span class="kw">type</span> ‘<span class="dt">T.Text</span>’</span>
|
||
<span id="cb318-11"><a href="#cb318-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">NB</span><span class="op">:</span> ‘<span class="dt">T.Text</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.Text.Internal</span>’</span>
|
||
<span id="cb318-12"><a href="#cb318-12" aria-hidden="true" tabindex="-1"></a> ‘<span class="dt">TL.Text</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.Text.Internal.Lazy</span>’</span>
|
||
<span id="cb318-13"><a href="#cb318-13" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">==</span>)’, namely ‘phrase’</span>
|
||
<span id="cb318-14"><a href="#cb318-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> lazyPhrase <span class="op">==</span> phrase</span>
|
||
<span id="cb318-15"><a href="#cb318-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> lazyPhrase <span class="op">==</span> phrase</span>
|
||
<span id="cb318-16"><a href="#cb318-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb318-17"><a href="#cb318-17" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> <span class="op">:</span>t TL.toStrict</span>
|
||
<span id="cb318-18"><a href="#cb318-18" aria-hidden="true" tabindex="-1"></a>TL.toStrict<span class="ot"> ::</span> <span class="dt">TL.Text</span> <span class="ot">-></span> <span class="dt">T.Text</span></span>
|
||
<span id="cb318-19"><a href="#cb318-19" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> <span class="op">:</span>t TL.fromStrict</span>
|
||
<span id="cb318-20"><a href="#cb318-20" aria-hidden="true" tabindex="-1"></a>TL.fromStrict<span class="ot"> ::</span> <span class="dt">T.Text</span> <span class="ot">-></span> <span class="dt">TL.Text</span></span>
|
||
<span id="cb318-21"><a href="#cb318-21" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">TL</span><span class="op">></span> TL.toStrict lazyPhrase <span class="op">==</span> phrase</span>
|
||
<span id="cb318-22"><a href="#cb318-22" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<h3 data-number="14.1.2" 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="cb319"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb319-1"><a href="#cb319-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Data.Word</span></span>
|
||
<span id="cb319-2"><a href="#cb319-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span><span class="op">></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></span>
|
||
<span id="cb319-3"><a href="#cb319-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> binary <span class="ot">=</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>]</span>
|
||
<span id="cb319-4"><a href="#cb319-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> <span class="op">:</span>t binary</span>
|
||
<span id="cb319-5"><a href="#cb319-5" aria-hidden="true" tabindex="-1"></a><span class="ot">binary ::</span> <span class="dt">B.ByteString</span></span>
|
||
<span id="cb319-6"><a href="#cb319-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> <span class="op">:</span>t B.pack</span>
|
||
<span id="cb319-7"><a href="#cb319-7" aria-hidden="true" tabindex="-1"></a>B.pack<span class="ot"> ::</span> [<span class="dt">Word8</span>] <span class="ot">-></span> <span class="dt">B.ByteString</span></span>
|
||
<span id="cb319-8"><a href="#cb319-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> binary</span>
|
||
<span id="cb319-9"><a href="#cb319-9" aria-hidden="true" tabindex="-1"></a><span class="st">"coffee"</span></span>
|
||
<span id="cb319-10"><a href="#cb319-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> <span class="op">:</span>t B.length</span>
|
||
<span id="cb319-11"><a href="#cb319-11" aria-hidden="true" tabindex="-1"></a>B.length<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb319-12"><a href="#cb319-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> B.length binary</span>
|
||
<span id="cb319-13"><a href="#cb319-13" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></span>
|
||
<span id="cb319-14"><a href="#cb319-14" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> <span class="op">:</span>t B.head</span>
|
||
<span id="cb319-15"><a href="#cb319-15" aria-hidden="true" tabindex="-1"></a>B.head<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">Word8</span></span>
|
||
<span id="cb319-16"><a href="#cb319-16" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> B.head binary</span>
|
||
<span id="cb319-17"><a href="#cb319-17" aria-hidden="true" tabindex="-1"></a><span class="dv">99</span></span>
|
||
<span id="cb319-18"><a href="#cb319-18" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> B.take <span class="dv">4</span> binary</span>
|
||
<span id="cb319-19"><a href="#cb319-19" aria-hidden="true" tabindex="-1"></a><span class="st">"coff"</span></span>
|
||
<span id="cb319-20"><a href="#cb319-20" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> <span class="op">:</span>t B.map</span>
|
||
<span id="cb319-21"><a href="#cb319-21" aria-hidden="true" tabindex="-1"></a>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></span>
|
||
<span id="cb319-22"><a href="#cb319-22" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></span> B.map (<span class="op">+</span><span class="dv">1</span>) binary</span>
|
||
<span id="cb319-23"><a href="#cb319-23" aria-hidden="true" tabindex="-1"></a><span class="st">"dpggff"</span></span></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="cb320"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb320-1"><a href="#cb320-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">B</span> <span class="dt">Data.Char</span><span class="op">></span> B.head (B.pack (<span class="fu">repeat</span> <span class="dv">99</span>))</span>
|
||
<span id="cb320-2"><a href="#cb320-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- never returns</span></span>
|
||
<span id="cb320-3"><a href="#cb320-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span><span class="op">></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">BL</span></span>
|
||
<span id="cb320-4"><a href="#cb320-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">BL</span><span class="op">></span> BL.head (BL.pack (<span class="fu">repeat</span> <span class="dv">99</span>))</span>
|
||
<span id="cb320-5"><a href="#cb320-5" aria-hidden="true" tabindex="-1"></a><span class="dv">99</span></span>
|
||
<span id="cb320-6"><a href="#cb320-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">BL</span><span class="op">></span> binary <span class="op">==</span> BL.pack [<span class="dv">99</span>]</span>
|
||
<span id="cb320-7"><a href="#cb320-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb320-8"><a href="#cb320-8" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb320-9"><a href="#cb320-9" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘<span class="dt">B.ByteString</span>’</span>
|
||
<span id="cb320-10"><a href="#cb320-10" aria-hidden="true" tabindex="-1"></a> with actual <span class="kw">type</span> ‘<span class="dt">BL.ByteString</span>’</span>
|
||
<span id="cb320-11"><a href="#cb320-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">NB</span><span class="op">:</span> ‘<span class="dt">BL.ByteString</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.ByteString.Lazy.Internal</span>’</span>
|
||
<span id="cb320-12"><a href="#cb320-12" aria-hidden="true" tabindex="-1"></a> ‘<span class="dt">B.ByteString</span>’ is defined <span class="kw">in</span> ‘<span class="dt">Data.ByteString.Internal</span>’</span>
|
||
<span id="cb320-13"><a href="#cb320-13" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">==</span>)’, namely ‘BL.pack [<span class="dv">99</span>]’</span>
|
||
<span id="cb320-14"><a href="#cb320-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> binary <span class="op">==</span> BL.pack [<span class="dv">99</span>]</span>
|
||
<span id="cb320-15"><a href="#cb320-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> binary <span class="op">==</span> BL.pack [<span class="dv">99</span>]</span>
|
||
<span id="cb320-16"><a href="#cb320-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb320-17"><a href="#cb320-17" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">BL</span><span class="op">></span> <span class="op">:</span>t BL.toStrict</span>
|
||
<span id="cb320-18"><a href="#cb320-18" aria-hidden="true" tabindex="-1"></a>BL.toStrict<span class="ot"> ::</span> <span class="dt">BL.ByteString</span> <span class="ot">-></span> <span class="dt">B.ByteString</span></span>
|
||
<span id="cb320-19"><a href="#cb320-19" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">BL</span><span class="op">></span> <span class="op">:</span>t BL.fromStrict</span>
|
||
<span id="cb320-20"><a href="#cb320-20" aria-hidden="true" tabindex="-1"></a>BL.fromStrict<span class="ot"> ::</span> <span class="dt">B.ByteString</span> <span class="ot">-></span> <span class="dt">BL.ByteString</span></span>
|
||
<span id="cb320-21"><a href="#cb320-21" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Word</span> <span class="dt">B</span> <span class="dt">BL</span><span class="op">></span> binary <span class="op">==</span> BL.toStrict (BL.pack [<span class="dv">99</span>])</span>
|
||
<span id="cb320-22"><a href="#cb320-22" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></code></pre></div>
|
||
<h3 data-number="14.1.3" 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 using 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="cb321"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb321-1"><a href="#cb321-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></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></span>
|
||
<span id="cb321-2"><a href="#cb321-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span><span class="op">></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></span>
|
||
<span id="cb321-3"><a href="#cb321-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="op">></span> T.length (T.pack <span class="st">"haskell"</span>)</span>
|
||
<span id="cb321-4"><a href="#cb321-4" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span></span>
|
||
<span id="cb321-5"><a href="#cb321-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="op">></span> T.length (T.pack <span class="st">"Ha∫keλ!"</span>)</span>
|
||
<span id="cb321-6"><a href="#cb321-6" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span></span>
|
||
<span id="cb321-7"><a href="#cb321-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Data.Text.Encoding</span></span>
|
||
<span id="cb321-8"><a href="#cb321-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="op">></span> encodeUtf8 (T.pack <span class="st">"haskell"</span>)</span>
|
||
<span id="cb321-9"><a href="#cb321-9" aria-hidden="true" tabindex="-1"></a><span class="st">"haskell"</span></span>
|
||
<span id="cb321-10"><a href="#cb321-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="op">></span> encodeUtf8 (T.pack <span class="st">"Ha∫keλ!"</span>)</span>
|
||
<span id="cb321-11"><a href="#cb321-11" aria-hidden="true" tabindex="-1"></a><span class="st">"Ha\226\136\171ke\206\187!"</span></span>
|
||
<span id="cb321-12"><a href="#cb321-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="op">></span> B.length (encodeUtf8 (T.pack <span class="st">"haskell"</span>))</span>
|
||
<span id="cb321-13"><a href="#cb321-13" aria-hidden="true" tabindex="-1"></a><span class="dv">7</span></span>
|
||
<span id="cb321-14"><a href="#cb321-14" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">Data.Text.Encoding</span><span class="op">></span> B.length (encodeUtf8 (T.pack <span class="st">"Ha∫keλ!"</span>))</span>
|
||
<span id="cb321-15"><a href="#cb321-15" aria-hidden="true" tabindex="-1"></a><span class="dv">10</span></span></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="cb322"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb322-1"><a href="#cb322-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span><span class="op">></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></span>
|
||
<span id="cb322-2"><a href="#cb322-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> B8.pack <span class="st">"abc"</span></span>
|
||
<span id="cb322-3"><a href="#cb322-3" aria-hidden="true" tabindex="-1"></a><span class="st">"abc"</span></span>
|
||
<span id="cb322-4"><a href="#cb322-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> <span class="op">:</span>t B8.pack</span>
|
||
<span id="cb322-5"><a href="#cb322-5" aria-hidden="true" tabindex="-1"></a>B8.pack<span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">B.ByteString</span></span>
|
||
<span id="cb322-6"><a href="#cb322-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> <span class="op">:</span>t B.pack</span>
|
||
<span id="cb322-7"><a href="#cb322-7" aria-hidden="true" tabindex="-1"></a>B.pack<span class="ot"> ::</span> [<span class="dt">Word8</span>] <span class="ot">-></span> <span class="dt">B.ByteString</span></span>
|
||
<span id="cb322-8"><a href="#cb322-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> B8.cons <span class="ch">'a'</span> (B8.pack <span class="st">"bc"</span>)</span>
|
||
<span id="cb322-9"><a href="#cb322-9" aria-hidden="true" tabindex="-1"></a><span class="st">"abc"</span></span>
|
||
<span id="cb322-10"><a href="#cb322-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> <span class="fu">putStrLn</span> (B8.unpack (B8.pack <span class="st">"€λ훈"</span>)) <span class="co">-- non-ASCII characters get truncated</span></span>
|
||
<span id="cb322-11"><a href="#cb322-11" aria-hidden="true" tabindex="-1"></a>¬»È</span>
|
||
<span id="cb322-12"><a href="#cb322-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">T</span> <span class="dt">B</span> <span class="dt">B8</span><span class="op">></span> <span class="fu">putStrLn</span> (T.unpack (T.pack <span class="st">"€λ훈"</span>))</span>
|
||
<span id="cb322-13"><a href="#cb322-13" aria-hidden="true" tabindex="-1"></a>€λ훈</span></code></pre></div>
|
||
<h2 data-number="14.2" 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="cb323"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb323-1"><a href="#cb323-1" aria-hidden="true" tabindex="-1"></a>foo y <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb323-2"><a href="#cb323-2" aria-hidden="true" tabindex="-1"></a> operation1 <span class="co">-- run an operation</span></span>
|
||
<span id="cb323-3"><a href="#cb323-3" aria-hidden="true" tabindex="-1"></a> val <span class="ot"><-</span> operation2 <span class="co">-- run an operation and keep the produced value</span></span>
|
||
<span id="cb323-4"><a href="#cb323-4" aria-hidden="true" tabindex="-1"></a> operation3 val y <span class="co">-- run an operation with parameters</span></span>
|
||
<span id="cb323-5"><a href="#cb323-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">mapM_</span> (\x <span class="ot">-></span> operation4 val x) things <span class="co">-- use a generic monad operation and a lambda</span></span>
|
||
<span id="cb323-6"><a href="#cb323-6" aria-hidden="true" tabindex="-1"></a> operation5 val <span class="co">-- the final line of the do decides which value the whole block produces</span></span></code></pre></div>
|
||
<!-- TODO more? -->
|
||
<h2 data-number="14.3" 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.3/docs/Network-Wai.html">WAI</a>
|
||
and <a href="https://hackage.haskell.org/package/warp-3.3.23">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="cb324"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb324-1"><a href="#cb324-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Examples.HelloServer</span> <span class="kw">where</span></span>
|
||
<span id="cb324-2"><a href="#cb324-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb324-3"><a href="#cb324-3" aria-hidden="true" tabindex="-1"></a><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">BL</span></span>
|
||
<span id="cb324-4"><a href="#cb324-4" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.HTTP.Types.Status</span> (status200)</span>
|
||
<span id="cb324-5"><a href="#cb324-5" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.Wai</span> (<span class="dt">Application</span>, responseLBS)</span>
|
||
<span id="cb324-6"><a href="#cb324-6" aria-hidden="true" tabindex="-1"></a><span class="kw">import</span> <span class="dt">Network.Wai.Handler.Warp</span> (run)</span>
|
||
<span id="cb324-7"><a href="#cb324-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb324-8"><a href="#cb324-8" aria-hidden="true" tabindex="-1"></a><span class="ot">port ::</span> <span class="dt">Int</span></span>
|
||
<span id="cb324-9"><a href="#cb324-9" aria-hidden="true" tabindex="-1"></a>port <span class="ot">=</span> <span class="dv">3421</span></span>
|
||
<span id="cb324-10"><a href="#cb324-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb324-11"><a href="#cb324-11" aria-hidden="true" tabindex="-1"></a><span class="ot">main ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb324-12"><a href="#cb324-12" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> run port application</span>
|
||
<span id="cb324-13"><a href="#cb324-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb324-14"><a href="#cb324-14" aria-hidden="true" tabindex="-1"></a><span class="co">-- type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived</span></span>
|
||
<span id="cb324-15"><a href="#cb324-15" aria-hidden="true" tabindex="-1"></a><span class="ot">application ::</span> <span class="dt">Application</span></span>
|
||
<span id="cb324-16"><a href="#cb324-16" aria-hidden="true" tabindex="-1"></a>application request respond <span class="ot">=</span></span>
|
||
<span id="cb324-17"><a href="#cb324-17" aria-hidden="true" tabindex="-1"></a> respond (responseLBS status200 [] (BL.pack <span class="st">"Hello World!"</span>))</span></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="https://hackage.haskell.org/package/warp-3.3.23/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="cb325"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb325-1"><a href="#cb325-1" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb325-2"><a href="#cb325-2" aria-hidden="true" tabindex="-1"></a><span class="kw">type</span> <span class="dt">Application</span> <span class="ot">=</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></span></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="https://hackage.haskell.org/package/warp-3.3.23/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.3/docs/Network-Wai.html#v:responseLBS"><code>responseLBS</code>
|
||
function</a> has the type</p>
|
||
<div class="sourceCode" id="cb326"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb326-1"><a href="#cb326-1" aria-hidden="true" tabindex="-1"></a><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></span></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.3/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="cb327"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb327-1"><a href="#cb327-1" aria-hidden="true" tabindex="-1"></a><span class="ot">pathInfo ::</span> <span class="dt">Request</span> <span class="ot">-></span> [<span class="dt">Text</span>]</span></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 data-number="14.4" 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.2">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="cb328"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb328-1"><a href="#cb328-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Database.SQLite.Simple</span></span>
|
||
<span id="cb328-2"><a href="#cb328-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="op">></span> <span class="op">:</span>t open</span>
|
||
<span id="cb328-3"><a href="#cb328-3" aria-hidden="true" tabindex="-1"></a><span class="ot">open ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Connection</span></span>
|
||
<span id="cb328-4"><a href="#cb328-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="op">></span> db <span class="ot"><-</span> open <span class="st">"example.sqlite"</span></span></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="cb329"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb329-1"><a href="#cb329-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="op">></span> <span class="op">:</span>t query_</span>
|
||
<span id="cb329-2"><a href="#cb329-2" aria-hidden="true" tabindex="-1"></a><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]</span>
|
||
<span id="cb329-3"><a href="#cb329-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="op">></span> <span class="op">:</span>info <span class="dt">Query</span></span>
|
||
<span id="cb329-4"><a href="#cb329-4" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">Query</span> <span class="ot">=</span> <span class="dt">Query</span> {<span class="ot">fromQuery ::</span> <span class="dt">Data.Text.Internal.Text</span>}</span>
|
||
<span id="cb329-5"><a href="#cb329-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Defined in ‘Database.SQLite.Simple.Types’</span></span>
|
||
<span id="cb329-6"><a href="#cb329-6" aria-hidden="true" tabindex="-1"></a> <span class="co">-- ... rest of output omitted</span></span>
|
||
<span id="cb329-7"><a href="#cb329-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span><span class="op">></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></span>
|
||
<span id="cb329-8"><a href="#cb329-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> q <span class="ot">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT 1;"</span>)</span>
|
||
<span id="cb329-9"><a href="#cb329-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> res <span class="ot"><-</span> query_ db<span class="ot"> q ::</span> <span class="dt">IO</span> [[<span class="dt">Int</span>]]</span>
|
||
<span id="cb329-10"><a href="#cb329-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> res</span>
|
||
<span id="cb329-11"><a href="#cb329-11" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">1</span>]]</span></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="cb330"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb330-1"><a href="#cb330-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> res <span class="ot"><-</span> query_ db q</span>
|
||
<span id="cb330-2"><a href="#cb330-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb330-3"><a href="#cb330-3" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">17</span><span class="op">:</span><span class="dv">8</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb330-4"><a href="#cb330-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Ambiguous</span> <span class="kw">type</span> variable ‘r0’ arising from a use <span class="kw">of</span> ‘query_’</span>
|
||
<span id="cb330-5"><a href="#cb330-5" aria-hidden="true" tabindex="-1"></a> prevents the constraint ‘(<span class="dt">FromRow</span> r0)’ from being solved<span class="op">.</span></span>
|
||
<span id="cb330-6"><a href="#cb330-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">Probable</span> fix<span class="op">:</span> use a <span class="kw">type</span> annotation to specify what ‘r0’ should be<span class="op">.</span></span>
|
||
<span id="cb330-7"><a href="#cb330-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- rest of error omitted</span></span></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.2/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="cb331"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb331-1"><a href="#cb331-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Int</span></span>
|
||
<span id="cb331-2"><a href="#cb331-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Bool</span></span>
|
||
<span id="cb331-3"><a href="#cb331-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">String</span></span>
|
||
<span id="cb331-4"><a href="#cb331-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromField</span> <span class="dt">Text</span></span>
|
||
<span id="cb331-5"><a href="#cb331-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">FromField</span> a <span class="ot">=></span> <span class="dt">FromRow</span> [a]</span>
|
||
<span id="cb331-6"><a href="#cb331-6" aria-hidden="true" tabindex="-1"></a><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)</span>
|
||
<span id="cb331-7"><a href="#cb331-7" aria-hidden="true" tabindex="-1"></a><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)</span></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="cb332"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb332-1"><a href="#cb332-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> q <span class="ot">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT 1, true, 'string';"</span>)</span>
|
||
<span id="cb332-2"><a href="#cb332-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></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>)]</span>
|
||
<span id="cb332-3"><a href="#cb332-3" aria-hidden="true" tabindex="-1"></a>[(<span class="dv">1</span>,<span class="dt">True</span>,<span class="st">"string"</span>)]</span></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="cb333"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb333-1"><a href="#cb333-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></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>)]</span>
|
||
<span id="cb333-2"><a href="#cb333-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Exception</span><span class="op">:</span> <span class="dt">ConversionFailed</span> {errSQLType <span class="ot">=</span> <span class="st">"TEXT"</span>, errHaskellType <span class="ot">=</span> <span class="st">"Int"</span>, errMessage <span class="ot">=</span> <span class="st">"need an int"</span>}</span></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="cb334"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb334-1"><a href="#cb334-1" aria-hidden="true" tabindex="-1"></a><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]</span></code></pre></div>
|
||
<p>And here are some instances for <code>ToRow</code> and
|
||
<code>ToField</code>:</p>
|
||
<div class="sourceCode" id="cb335"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb335-1"><a href="#cb335-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Int</span></span>
|
||
<span id="cb335-2"><a href="#cb335-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Bool</span></span>
|
||
<span id="cb335-3"><a href="#cb335-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">String</span></span>
|
||
<span id="cb335-4"><a href="#cb335-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Text</span></span>
|
||
<span id="cb335-5"><a href="#cb335-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> <span class="dt">Int</span></span>
|
||
<span id="cb335-6"><a href="#cb335-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb335-7"><a href="#cb335-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> a <span class="ot">=></span> <span class="dt">ToRow</span> [a]</span>
|
||
<span id="cb335-8"><a href="#cb335-8" aria-hidden="true" tabindex="-1"></a><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)</span>
|
||
<span id="cb335-9"><a href="#cb335-9" aria-hidden="true" tabindex="-1"></a><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)</span>
|
||
<span id="cb335-10"><a href="#cb335-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">ToField</span> a <span class="ot">=></span> <span class="dt">ToRow</span> (<span class="dt">Only</span> a)</span></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="cb336"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb336-1"><a href="#cb336-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> input <span class="ot">=</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>)</span>
|
||
<span id="cb336-2"><a href="#cb336-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> parameterized <span class="ot">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT ?+1, true, ?;"</span>)</span>
|
||
<span id="cb336-3"><a href="#cb336-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></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>)]</span>
|
||
<span id="cb336-4"><a href="#cb336-4" aria-hidden="true" tabindex="-1"></a>[(<span class="dv">2</span>,<span class="dt">True</span>,<span class="st">"hello"</span>)]</span></code></pre></div>
|
||
<p><strong>Note!</strong> When performing a query with only one
|
||
parameter, there are two <code>ToRow</code> instances you can use:
|
||
<code>ToField a => ToRow [a]</code> and
|
||
<code>ToField a => Only a</code>. The <code>Only</code> datatype is
|
||
defined in <code>Data.Tuple.Only</code> and is kind of a workaround for
|
||
the fact that Haskell doesn’t have one-element tuples. Alternatively, a
|
||
list of size 1 works as well. The same applies for queries that return
|
||
rows with only one column: you can use either <code>[[X]]</code> or
|
||
<code>[Only X]</code> as the return type. Here’s an example:</p>
|
||
<div class="sourceCode" id="cb337"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb337-1"><a href="#cb337-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> q <span class="ot">=</span> <span class="dt">Query</span> (T.pack <span class="st">"SELECT lower(?);"</span>)</span>
|
||
<span id="cb337-2"><a href="#cb337-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> query db q (<span class="dt">Only</span> <span class="st">"HELLO"</span>)<span class="ot"> ::</span> <span class="dt">IO</span> [<span class="dt">Only</span> <span class="dt">String</span>]</span>
|
||
<span id="cb337-3"><a href="#cb337-3" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Only</span> {fromOnly <span class="ot">=</span> <span class="st">"hello"</span>}]</span>
|
||
<span id="cb337-4"><a href="#cb337-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Database.SQLite.Simple</span> <span class="dt">T</span><span class="op">></span> query db q [<span class="st">"HELLO"</span>]<span class="ot"> ::</span> <span class="dt">IO</span> [[<span class="dt">String</span>]]</span>
|
||
<span id="cb337-5"><a href="#cb337-5" aria-hidden="true" tabindex="-1"></a>[[<span class="st">"hello"</span>]]</span></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="cb338"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb338-1"><a href="#cb338-1" aria-hidden="true" tabindex="-1"></a><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> ()</span>
|
||
<span id="cb338-2"><a href="#cb338-2" aria-hidden="true" tabindex="-1"></a><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> ()</span></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 data-number="14.5" 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>
|
||
</ul>
|
||
<h1 data-number="15"
|
||
id="lecture-15-youre-valid-even-without-monads"><span
|
||
class="header-section-number">15</span> Lecture 15: You’re Valid Even
|
||
Without Monads</h1>
|
||
<h2 data-number="15.1" id="introduction-to-applicatives"><span
|
||
class="header-section-number">15.1</span> Introduction to
|
||
Applicatives</h2>
|
||
<p>The <code>Applicative</code> type class is a middle ground between
|
||
<code>Functor</code> (which you can’t do that much with) and
|
||
<code>Monad</code> (which pretty much allows you to write arbitrary
|
||
programs). Reasons to use <code>Applicative</code> instead of
|
||
<code>Monad</code> include:</p>
|
||
<ul>
|
||
<li>Performance: since <code>Applicative</code> allows less operations,
|
||
it can be optimized better than <code>Monad</code>.</li>
|
||
<li>Simplicity: an <code>Applicative</code> interface is easier to
|
||
reason about.</li>
|
||
<li>Necessity: there just is no way to define a <code>Monad</code>
|
||
instance for your type, but there is an <code>Applicative</code>
|
||
instance. This is rare.</li>
|
||
</ul>
|
||
<p>So what is an <code>Applicative</code>? Let’s look at a
|
||
definition.</p>
|
||
<div class="sourceCode" id="cb340"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb340-1"><a href="#cb340-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="ot">=></span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
|
||
<span id="cb340-2"><a href="#cb340-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> pure ::</span> a <span class="ot">-></span> f a</span>
|
||
<span id="cb340-3"><a href="#cb340-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> liftA2 ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> f a <span class="ot">-></span> f b <span class="ot">-></span> f c</span>
|
||
<span id="cb340-4"><a href="#cb340-4" aria-hidden="true" tabindex="-1"></a> <span class="co">-- other operations omitted for now</span></span></code></pre></div>
|
||
<p>So an <code>Applicative</code> is a <code>Functor</code> that allows
|
||
us to build singleton values via <code>pure</code>, and combine two
|
||
values into one using <code>liftA2</code>. This adds a lot of power
|
||
compared to a bare functor. Computations using functors are necessarily
|
||
linear: <code>fmap :: (a -> b) -> f a -> f b</code> takes in
|
||
one functorial value, and outputs another. By contrast,
|
||
<code>pure</code> takes in no functorial value and outputs one, and
|
||
<code>liftA2</code> takes in two and returns one.</p>
|
||
<p>Sidenote: the term Applicative comes from the term <a
|
||
href="https://en.wikipedia.org/wiki/Applicative_functor">Applicative
|
||
Functor</a>, which sounds like it comes from Category Theory, but was
|
||
actually introduced in a programming paper.</p>
|
||
<p>That’s enough abstract mumbo jumbo for now. Let’s look at what sort
|
||
of computations we can express using Applicative operations (and
|
||
<code>fmap</code>). We’ll start with the <code>Maybe</code> applicative.
|
||
Here’s a streamlined definition:</p>
|
||
<div class="sourceCode" id="cb341"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb341-1"><a href="#cb341-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
|
||
<span id="cb341-2"><a href="#cb341-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">pure</span> x <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb341-3"><a href="#cb341-3" aria-hidden="true" tabindex="-1"></a> liftA2 f (<span class="dt">Just</span> x) (<span class="dt">Just</span> y) <span class="ot">=</span> <span class="dt">Just</span> (f x y)</span>
|
||
<span id="cb341-4"><a href="#cb341-4" aria-hidden="true" tabindex="-1"></a> liftA2 f _ _ <span class="ot">=</span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<!-- TODO some GHCi examples? -->
|
||
<p>You’ll see the definition uses the same type of failure propagation
|
||
as the <code>Monad Maybe</code> instance. Let’s use this when parsing
|
||
monetary values:</p>
|
||
<div class="sourceCode" id="cb342"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb342-1"><a href="#cb342-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Currency</span> <span class="ot">=</span> <span class="dt">EUR</span> <span class="op">|</span> <span class="dt">USD</span></span>
|
||
<span id="cb342-2"><a href="#cb342-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb342-3"><a href="#cb342-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Money</span> <span class="dt">Int</span> <span class="dt">Currency</span></span>
|
||
<span id="cb342-4"><a href="#cb342-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb342-5"><a href="#cb342-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb342-6"><a href="#cb342-6" aria-hidden="true" tabindex="-1"></a><span class="ot">parseCurrency ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Currency</span></span>
|
||
<span id="cb342-7"><a href="#cb342-7" aria-hidden="true" tabindex="-1"></a>parseCurrency <span class="st">"e"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">EUR</span></span>
|
||
<span id="cb342-8"><a href="#cb342-8" aria-hidden="true" tabindex="-1"></a>parseCurrency <span class="st">"€"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">EUR</span></span>
|
||
<span id="cb342-9"><a href="#cb342-9" aria-hidden="true" tabindex="-1"></a>parseCurrency <span class="st">"$"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">USD</span></span>
|
||
<span id="cb342-10"><a href="#cb342-10" aria-hidden="true" tabindex="-1"></a>parseCurrency _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb342-11"><a href="#cb342-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb342-12"><a href="#cb342-12" aria-hidden="true" tabindex="-1"></a><span class="ot">parseAmount ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb342-13"><a href="#cb342-13" aria-hidden="true" tabindex="-1"></a>parseAmount <span class="ot">=</span> readMaybe</span>
|
||
<span id="cb342-14"><a href="#cb342-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb342-15"><a href="#cb342-15" aria-hidden="true" tabindex="-1"></a><span class="ot">parseMoney ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Money</span></span>
|
||
<span id="cb342-16"><a href="#cb342-16" aria-hidden="true" tabindex="-1"></a>parseMoney amountString currencyString <span class="ot">=</span></span>
|
||
<span id="cb342-17"><a href="#cb342-17" aria-hidden="true" tabindex="-1"></a> liftA2 <span class="dt">Money</span> (parseAmount amountString) (parseCurrency currencyString)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb343"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb343-1"><a href="#cb343-1" aria-hidden="true" tabindex="-1"></a>parseMoney <span class="st">"123"</span> <span class="st">"€"</span> <span class="op">==></span> <span class="dt">Just</span> (<span class="dt">Money</span> <span class="dv">123</span> <span class="dt">EUR</span>)</span>
|
||
<span id="cb343-2"><a href="#cb343-2" aria-hidden="true" tabindex="-1"></a>parseMoney <span class="st">"45"</span> <span class="st">"$"</span> <span class="op">==></span> <span class="dt">Just</span> (<span class="dt">Money</span> <span class="dv">45</span> <span class="dt">USD</span>)</span>
|
||
<span id="cb343-3"><a href="#cb343-3" aria-hidden="true" tabindex="-1"></a>parseMoney <span class="st">"4x"</span> <span class="st">"€"</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb343-4"><a href="#cb343-4" aria-hidden="true" tabindex="-1"></a>parseMoney <span class="st">"45"</span> <span class="st">"£"</span> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>That worked out nicely. However, if we try to expand on this we soon
|
||
run into the limits of <code>Applicative</code>. For example, consider
|
||
this <code>sumMoney</code> function that sums <code>Money</code> values
|
||
but fails if they are not in the same currency:</p>
|
||
<div class="sourceCode" id="cb344"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb344-1"><a href="#cb344-1" aria-hidden="true" tabindex="-1"></a><span class="ot">sumMoney ::</span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Money</span></span>
|
||
<span id="cb344-2"><a href="#cb344-2" aria-hidden="true" tabindex="-1"></a>sumMoney (<span class="dt">Money</span> a c) (<span class="dt">Money</span> b c')</span>
|
||
<span id="cb344-3"><a href="#cb344-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> c <span class="op">==</span> c' <span class="ot">=</span> <span class="dt">Just</span> (<span class="dt">Money</span> (a<span class="op">+</span>b) c)</span>
|
||
<span id="cb344-4"><a href="#cb344-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>We can’t apply it to two <code>Maybe Money</code> values using
|
||
<code>Applicative</code> operations. We need the <code>Maybe</code>
|
||
monad for that:</p>
|
||
<div class="sourceCode" id="cb345"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb345-1"><a href="#cb345-1" aria-hidden="true" tabindex="-1"></a><span class="ot">example ::</span> <span class="dt">Maybe</span> <span class="dt">Money</span></span>
|
||
<span id="cb345-2"><a href="#cb345-2" aria-hidden="true" tabindex="-1"></a>example <span class="ot">=</span> <span class="kw">do</span> x <span class="ot"><-</span> parseMoney <span class="st">"123"</span> <span class="st">"€"</span></span>
|
||
<span id="cb345-3"><a href="#cb345-3" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> parseMoney <span class="st">"45"</span> <span class="st">"$"</span></span>
|
||
<span id="cb345-4"><a href="#cb345-4" aria-hidden="true" tabindex="-1"></a> sumMoney x y</span></code></pre></div>
|
||
<p>If we try to use <code>liftA2</code>, we’re stuck with a
|
||
<code>Maybe (Maybe Money)</code> type. In addition, we can now get two
|
||
different types of failures: <code>Nothing</code> and
|
||
<code>Just Nothing</code>, depending on what level the error happens on.
|
||
This would be a clear case for switching to a <code>Monad</code>
|
||
instance.</p>
|
||
<pre><code>liftA2 sumMoney (parseMoney "123" "e") (parseMoney "45" "€")
|
||
==> Just (Just (Money 168 EUR))
|
||
liftA2 sumMoney (parseMoney "123" "e") (parseMoney "45" "$")
|
||
==> Just Nothing
|
||
liftA2 sumMoney (parseMoney "123" "e") (parseMoney "xxx" "e")
|
||
==> Nothing</code></pre>
|
||
<p>Sidenote: the name <code>liftA2</code> sounds a bit cumbersome, but
|
||
it’s an analogy with the <code>liftM</code>, <code>liftM2</code> and so
|
||
on functions for monads. Recall that <code>liftM</code> was just
|
||
<code>fmap</code>, so perhaps <code>liftA2</code> should’ve been called
|
||
<code>fmap2</code>.</p>
|
||
<h2 data-number="15.2" id="the-list-applicative"><span
|
||
class="header-section-number">15.2</span> The List Applicative</h2>
|
||
<p>Let’s have a look at the applicative instances for another
|
||
<code>Functor</code> we’ve seen. The <code>Applicative</code> instance
|
||
for the list functor goes through all possible combinations of values
|
||
(just like the list monad). Here’s the instance:</p>
|
||
<div class="sourceCode" id="cb347"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb347-1"><a href="#cb347-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> [] <span class="kw">where</span></span>
|
||
<span id="cb347-2"><a href="#cb347-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">pure</span> x <span class="ot">=</span> [x]</span>
|
||
<span id="cb347-3"><a href="#cb347-3" aria-hidden="true" tabindex="-1"></a> liftA2 f xs ys <span class="ot">=</span> [f x y <span class="op">|</span> x <span class="ot"><-</span> xs, y <span class="ot"><-</span> ys]</span></code></pre></div>
|
||
<p>And here’s an example: generating some phrases.</p>
|
||
<div class="sourceCode" id="cb348"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb348-1"><a href="#cb348-1" aria-hidden="true" tabindex="-1"></a><span class="ot">things ::</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb348-2"><a href="#cb348-2" aria-hidden="true" tabindex="-1"></a>things <span class="ot">=</span> [<span class="st">"tangerine"</span>,<span class="st">"bandit"</span>,<span class="st">"diamond"</span>]</span>
|
||
<span id="cb348-3"><a href="#cb348-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb348-4"><a href="#cb348-4" aria-hidden="true" tabindex="-1"></a><span class="ot">fruits ::</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb348-5"><a href="#cb348-5" aria-hidden="true" tabindex="-1"></a>fruits <span class="ot">=</span> [<span class="st">"apple"</span>, <span class="st">"tangerine"</span>]</span>
|
||
<span id="cb348-6"><a href="#cb348-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb348-7"><a href="#cb348-7" aria-hidden="true" tabindex="-1"></a><span class="ot">phrases ::</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb348-8"><a href="#cb348-8" aria-hidden="true" tabindex="-1"></a>phrases <span class="ot">=</span> liftA2 combine things fruits</span>
|
||
<span id="cb348-9"><a href="#cb348-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> combine t f <span class="ot">=</span> <span class="st">"a "</span> <span class="op">++</span> t <span class="op">++</span> <span class="st">" the size of a "</span> <span class="op">++</span> f</span>
|
||
<span id="cb348-10"><a href="#cb348-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb348-11"><a href="#cb348-11" aria-hidden="true" tabindex="-1"></a>bunches <span class="ot">=</span> liftA2 copy [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] fruits</span>
|
||
<span id="cb348-12"><a href="#cb348-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> copy n f <span class="ot">=</span> <span class="fu">unwords</span> (<span class="fu">replicate</span> n f)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb349"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb349-1"><a href="#cb349-1" aria-hidden="true" tabindex="-1"></a>phrases <span class="op">==></span> [<span class="st">"a tangerine the size of a apple"</span>,</span>
|
||
<span id="cb349-2"><a href="#cb349-2" aria-hidden="true" tabindex="-1"></a> <span class="st">"a tangerine the size of a tangerine"</span>,</span>
|
||
<span id="cb349-3"><a href="#cb349-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"a bandit the size of a apple"</span>,</span>
|
||
<span id="cb349-4"><a href="#cb349-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"a bandit the size of a tangerine"</span>,</span>
|
||
<span id="cb349-5"><a href="#cb349-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"a diamond the size of a apple"</span>,</span>
|
||
<span id="cb349-6"><a href="#cb349-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"a diamond the size of a tangerine"</span>]</span>
|
||
<span id="cb349-7"><a href="#cb349-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb349-8"><a href="#cb349-8" aria-hidden="true" tabindex="-1"></a>bunches <span class="op">==></span> [<span class="st">"apple"</span>,<span class="st">"tangerine"</span>,</span>
|
||
<span id="cb349-9"><a href="#cb349-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"apple apple"</span>,<span class="st">"tangerine tangerine"</span>,</span>
|
||
<span id="cb349-10"><a href="#cb349-10" aria-hidden="true" tabindex="-1"></a> <span class="st">"apple apple apple"</span>,<span class="st">"tangerine tangerine tangerine"</span>]</span></code></pre></div>
|
||
<!-- TODO more examples? -->
|
||
<h2 data-number="15.3" id="new-operators"><span
|
||
class="header-section-number">15.3</span> New Operators</h2>
|
||
<p>There are a handful of operators for Applicatives that are quite
|
||
handy. They are <code><$></code>, <code><*></code>,
|
||
<code><*</code> and <code>*></code>.</p>
|
||
<p>Let’s start with <code><$></code>, which is just an infix
|
||
version of <code>fmap</code>:</p>
|
||
<div class="sourceCode" id="cb350"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb350-1"><a href="#cb350-1" aria-hidden="true" tabindex="-1"></a><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</span>
|
||
<span id="cb350-2"><a href="#cb350-2" aria-hidden="true" tabindex="-1"></a>f <span class="op"><$></span> x <span class="ot">=</span> <span class="fu">fmap</span> f x</span></code></pre></div>
|
||
<div class="sourceCode" id="cb351"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb351-1"><a href="#cb351-1" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="op"><$></span> <span class="dt">Just</span> <span class="dt">True</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">False</span></span>
|
||
<span id="cb351-2"><a href="#cb351-2" aria-hidden="true" tabindex="-1"></a><span class="fu">not</span> <span class="op"><$></span> <span class="dt">Nothing</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb351-3"><a href="#cb351-3" aria-hidden="true" tabindex="-1"></a><span class="fu">negate</span> <span class="op"><$></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> [<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="op">-</span><span class="dv">3</span>]</span></code></pre></div>
|
||
<p>That’s kinda nice on its own, but it really gets to shine when
|
||
combined with this Applicative operator:</p>
|
||
<div class="sourceCode" id="cb352"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb352-1"><a href="#cb352-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(<*>) ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> f (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</span></code></pre></div>
|
||
<p>The type tells you what <code><*></code> does: it’s function
|
||
application <em>lifted</em> to an applicative. Here are some standalone
|
||
examples:</p>
|
||
<div class="sourceCode" id="cb353"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb353-1"><a href="#cb353-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="fu">not</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dt">True</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">False</span></span>
|
||
<span id="cb353-2"><a href="#cb353-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dt">True</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb353-3"><a href="#cb353-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="fu">not</span> <span class="op"><*></span> <span class="dt">Nothing</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb353-4"><a href="#cb353-4" aria-hidden="true" tabindex="-1"></a>[(<span class="op">+</span><span class="dv">1</span>),(<span class="op">*</span><span class="dv">2</span>)] <span class="op"><*></span> [<span class="dv">10</span>,<span class="dv">100</span>] <span class="op">==></span> [<span class="dv">11</span>,<span class="dv">101</span>,<span class="dv">20</span>,<span class="dv">200</span>]</span></code></pre></div>
|
||
<p>The real magic happens when we combine <code><$></code> and
|
||
<code><*></code>: we can then lift functions of arbitrarily many
|
||
arguments to an Applicative!</p>
|
||
<div class="sourceCode" id="cb354"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb354-1"><a href="#cb354-1" aria-hidden="true" tabindex="-1"></a><span class="ot">say ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb354-2"><a href="#cb354-2" aria-hidden="true" tabindex="-1"></a>say x i y <span class="ot">=</span> x <span class="op">++</span> <span class="st">" has "</span> <span class="op">++</span> <span class="fu">show</span> i <span class="op">++</span> <span class="st">" "</span> <span class="op">++</span> y</span></code></pre></div>
|
||
<div class="sourceCode" id="cb355"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb355-1"><a href="#cb355-1" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb355-2"><a href="#cb355-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> <span class="st">"haskell has 99 operators"</span></span>
|
||
<span id="cb355-3"><a href="#cb355-3" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> <span class="dt">Nothing</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb355-4"><a href="#cb355-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb355-5"><a href="#cb355-5" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> [<span class="st">"bob"</span>,<span class="st">"jake"</span>] <span class="op"><*></span> [<span class="dv">2</span>,<span class="dv">3</span>] <span class="op"><*></span> [<span class="st">"bananas"</span>,<span class="st">"cars"</span>]</span>
|
||
<span id="cb355-6"><a href="#cb355-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"bob has 2 bananas"</span>,</span>
|
||
<span id="cb355-7"><a href="#cb355-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"bob has 2 cars"</span>,</span>
|
||
<span id="cb355-8"><a href="#cb355-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"bob has 3 bananas"</span>,</span>
|
||
<span id="cb355-9"><a href="#cb355-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"bob has 3 cars"</span>,</span>
|
||
<span id="cb355-10"><a href="#cb355-10" aria-hidden="true" tabindex="-1"></a> <span class="st">"jake has 2 bananas"</span>,</span>
|
||
<span id="cb355-11"><a href="#cb355-11" aria-hidden="true" tabindex="-1"></a> <span class="st">"jake has 2 cars"</span>,</span>
|
||
<span id="cb355-12"><a href="#cb355-12" aria-hidden="true" tabindex="-1"></a> <span class="st">"jake has 3 bananas"</span>,</span>
|
||
<span id="cb355-13"><a href="#cb355-13" aria-hidden="true" tabindex="-1"></a> <span class="st">"jake has 3 cars"</span>]</span></code></pre></div>
|
||
<p>What’s going on here? Let’s step through the evaluation. The key is
|
||
that each <code><*></code> partially applies one more argument to
|
||
the function.</p>
|
||
<div class="sourceCode" id="cb356"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb356-1"><a href="#cb356-1" aria-hidden="true" tabindex="-1"></a> say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb356-2"><a href="#cb356-2" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> ((say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb356-3"><a href="#cb356-3" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> (<span class="fu">fmap</span> say (<span class="dt">Just</span> <span class="st">"haskell"</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb356-4"><a href="#cb356-4" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> (<span class="dt">Just</span> (say <span class="st">"haskell"</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb356-5"><a href="#cb356-5" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">Just</span> (say <span class="st">"haskell"</span> <span class="dv">99</span>) <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span></span>
|
||
<span id="cb356-6"><a href="#cb356-6" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">Just</span> (say <span class="st">"haskell"</span> <span class="dv">99</span> <span class="st">"operators"</span>)</span>
|
||
<span id="cb356-7"><a href="#cb356-7" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> <span class="dt">Just</span> <span class="st">"haskell has 99 operators"</span></span></code></pre></div>
|
||
<p>Perhaps looking at the types will make it clearer:</p>
|
||
<div class="sourceCode" id="cb357"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb357-1"><a href="#cb357-1" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> (<span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span>)</span>
|
||
<span id="cb357-2"><a href="#cb357-2" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span><span class="ot"> ::</span> <span class="dt">Maybe</span> ( <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span>)</span>
|
||
<span id="cb357-3"><a href="#cb357-3" aria-hidden="true" tabindex="-1"></a>say <span class="op"><$></span> <span class="dt">Just</span> <span class="st">"haskell"</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="dv">99</span> <span class="op"><*></span> <span class="dt">Just</span> <span class="st">"operators"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> ( <span class="dt">String</span>)</span></code></pre></div>
|
||
<p>The next two operators are a bit simpler:</p>
|
||
<div class="sourceCode" id="cb358"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb358-1"><a href="#cb358-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(*>) ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> f a <span class="ot">-></span> f b <span class="ot">-></span> f b</span>
|
||
<span id="cb358-2"><a href="#cb358-2" aria-hidden="true" tabindex="-1"></a>x <span class="op">*></span> y <span class="ot">=</span> liftA2 (\a b <span class="ot">-></span> b) x y</span>
|
||
<span id="cb358-3"><a href="#cb358-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb358-4"><a href="#cb358-4" aria-hidden="true" tabindex="-1"></a><span class="ot">(<*) ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> f a <span class="ot">-></span> f b <span class="ot">-></span> f a</span>
|
||
<span id="cb358-5"><a href="#cb358-5" aria-hidden="true" tabindex="-1"></a>x <span class="op"><*</span> y <span class="ot">=</span> liftA2 (\a b <span class="ot">-></span> a) x y</span></code></pre></div>
|
||
<p>You can compare the types to a more familiar operator:</p>
|
||
<div class="sourceCode" id="cb359"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb359-1"><a href="#cb359-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(>>) ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> m a <span class="ot">-></span> m b <span class="ot">-></span> m b</span></code></pre></div>
|
||
<p>What the operators <code><*</code> and <code>*></code> mean is:
|
||
run both of these operations, but only keep one result. The arrow points
|
||
to the result that’s kept:</p>
|
||
<div class="sourceCode" id="cb360"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb360-1"><a href="#cb360-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">1</span> <span class="op">*></span> <span class="dt">Just</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">2</span></span>
|
||
<span id="cb360-2"><a href="#cb360-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">1</span> <span class="op"><*</span> <span class="dt">Just</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">1</span></span>
|
||
<span id="cb360-3"><a href="#cb360-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">1</span> <span class="op"><*</span> <span class="dt">Nothing</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb360-4"><a href="#cb360-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span> <span class="op"><*</span> <span class="dt">Just</span> <span class="dv">2</span> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>These operators might seem trivial, but they’re useful when combining
|
||
checks. For example:</p>
|
||
<div class="sourceCode" id="cb361"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb361-1"><a href="#cb361-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decrease ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb361-2"><a href="#cb361-2" aria-hidden="true" tabindex="-1"></a>decrease i <span class="ot">=</span> <span class="kw">if</span> i<span class="op">></span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (i<span class="op">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb361-3"><a href="#cb361-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb361-4"><a href="#cb361-4" aria-hidden="true" tabindex="-1"></a><span class="ot">small ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb361-5"><a href="#cb361-5" aria-hidden="true" tabindex="-1"></a>small i <span class="ot">=</span> <span class="kw">if</span> i<span class="op"><</span><span class="dv">10</span> <span class="kw">then</span> <span class="dt">Just</span> i <span class="kw">else</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb361-6"><a href="#cb361-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb361-7"><a href="#cb361-7" aria-hidden="true" tabindex="-1"></a><span class="ot">decreaseSmall ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb361-8"><a href="#cb361-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- do what decrease does, but fail if small fails</span></span>
|
||
<span id="cb361-9"><a href="#cb361-9" aria-hidden="true" tabindex="-1"></a>decreaseSmall i <span class="ot">=</span> decrease i <span class="op"><*</span> small i</span></code></pre></div>
|
||
<div class="sourceCode" id="cb362"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb362-1"><a href="#cb362-1" aria-hidden="true" tabindex="-1"></a>decreaseSmall <span class="dv">4</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dv">3</span></span>
|
||
<span id="cb362-2"><a href="#cb362-2" aria-hidden="true" tabindex="-1"></a>decreaseSmall <span class="dv">0</span> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb362-3"><a href="#cb362-3" aria-hidden="true" tabindex="-1"></a>decreaseSmall <span class="dv">11</span> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>Now that we’ve seen all these operators, we can understand the full
|
||
definition of <code>Applicative</code>. All the operators have
|
||
definitions in terms of <code>liftA2</code>, so it’s enought to define
|
||
<code>liftA2</code> and <code>pure</code> when implementing an
|
||
<code>Applicative</code> instance.</p>
|
||
<div class="sourceCode" id="cb363"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb363-1"><a href="#cb363-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Functor</span> f <span class="ot">=></span> <span class="dt">Applicative</span> f <span class="kw">where</span></span>
|
||
<span id="cb363-2"><a href="#cb363-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> pure ::</span> a <span class="ot">-></span> f a</span>
|
||
<span id="cb363-3"><a href="#cb363-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> liftA2 ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> f a <span class="ot">-></span> f b <span class="ot">-></span> f c</span>
|
||
<span id="cb363-4"><a href="#cb363-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<*>) ::</span> f (a <span class="ot">-></span> b) <span class="ot">-></span> f a <span class="ot">-></span> f b</span>
|
||
<span id="cb363-5"><a href="#cb363-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> (*>) ::</span> f a <span class="ot">-></span> f b <span class="ot">-></span> f b</span>
|
||
<span id="cb363-6"><a href="#cb363-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<*) ::</span> f a <span class="ot">-></span> f b <span class="ot">-></span> f a</span></code></pre></div>
|
||
<h2 data-number="15.4" id="the-validation-applicative"><span
|
||
class="header-section-number">15.4</span> The Validation
|
||
Applicative</h2>
|
||
<p>Let’s look at an Applicative that’s a bit more interesting than Maybe
|
||
or lists. Often in programming we need to <em>validate</em> some inputs
|
||
from the user. In these cases it’s useful to gather together all the
|
||
errors that the input might have. The file <a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/Validation.hs"><code>exercises/Examples/Validation.hs</code></a>
|
||
implements the <code>Validation</code> datatype:</p>
|
||
<div class="sourceCode" id="cb364"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb364-1"><a href="#cb364-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Validation</span> a <span class="ot">=</span> <span class="dt">Ok</span> a <span class="op">|</span> <span class="dt">Errors</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb364-2"><a href="#cb364-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>,<span class="dt">Eq</span>)</span></code></pre></div>
|
||
<p>The <code>Applicative</code> instance for <code>Validation</code>
|
||
works like this:</p>
|
||
<div class="sourceCode" id="cb365"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb365-1"><a href="#cb365-1" aria-hidden="true" tabindex="-1"></a>liftA2 (<span class="op">+</span>) (<span class="dt">Ok</span> <span class="dv">1</span>) (<span class="dt">Ok</span> <span class="dv">2</span>)</span>
|
||
<span id="cb365-2"><a href="#cb365-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> <span class="dv">3</span></span>
|
||
<span id="cb365-3"><a href="#cb365-3" aria-hidden="true" tabindex="-1"></a>liftA2 (<span class="op">+</span>) (<span class="dt">Errors</span> [<span class="st">"oh no"</span>]) (<span class="dt">Errors</span> [<span class="st">"boom"</span>])</span>
|
||
<span id="cb365-4"><a href="#cb365-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"oh no"</span>,<span class="st">"boom"</span>]</span></code></pre></div>
|
||
<p>Note how in contrast to the <code>Maybe</code> Applicative, we have
|
||
many different kinds of failures.</p>
|
||
<p>Here’s a worked example that introduces some helpers and then uses
|
||
them to congratulate somebody on their birthday:</p>
|
||
<div class="sourceCode" id="cb366"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb366-1"><a href="#cb366-1" aria-hidden="true" tabindex="-1"></a><span class="ot">invalid ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> a</span>
|
||
<span id="cb366-2"><a href="#cb366-2" aria-hidden="true" tabindex="-1"></a>invalid err <span class="ot">=</span> <span class="dt">Errors</span> [err]</span>
|
||
<span id="cb366-3"><a href="#cb366-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb366-4"><a href="#cb366-4" aria-hidden="true" tabindex="-1"></a><span class="ot">check ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Validation</span> a</span>
|
||
<span id="cb366-5"><a href="#cb366-5" aria-hidden="true" tabindex="-1"></a>check b err x</span>
|
||
<span id="cb366-6"><a href="#cb366-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> b <span class="ot">=</span> <span class="fu">pure</span> x</span>
|
||
<span id="cb366-7"><a href="#cb366-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> invalid err</span>
|
||
<span id="cb366-8"><a href="#cb366-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb366-9"><a href="#cb366-9" aria-hidden="true" tabindex="-1"></a><span class="ot">birthday ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">String</span></span>
|
||
<span id="cb366-10"><a href="#cb366-10" aria-hidden="true" tabindex="-1"></a>birthday name age <span class="ot">=</span> liftA2 congratulate checkedName checkedAge</span>
|
||
<span id="cb366-11"><a href="#cb366-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> checkedName <span class="ot">=</span> check (<span class="fu">length</span> name <span class="op"><</span> <span class="dv">10</span>) <span class="st">"Name too long"</span> name</span>
|
||
<span id="cb366-12"><a href="#cb366-12" aria-hidden="true" tabindex="-1"></a> checkedAge <span class="ot">=</span> check (age <span class="op"><</span> <span class="dv">99</span>) <span class="st">"Too old"</span> age</span>
|
||
<span id="cb366-13"><a href="#cb366-13" aria-hidden="true" tabindex="-1"></a> congratulate n a <span class="ot">=</span> <span class="st">"Happy "</span><span class="op">++</span><span class="fu">show</span> a<span class="op">++</span><span class="st">"th birthday "</span><span class="op">++</span>n<span class="op">++</span><span class="st">"!"</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb367"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb367-1"><a href="#cb367-1" aria-hidden="true" tabindex="-1"></a>birthday <span class="st">"Guy"</span> <span class="dv">31</span></span>
|
||
<span id="cb367-2"><a href="#cb367-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> <span class="st">"Happy 31th birthday Guy!"</span></span>
|
||
<span id="cb367-3"><a href="#cb367-3" aria-hidden="true" tabindex="-1"></a>birthday <span class="st">"Guybrush Threepwood"</span> <span class="dv">31</span></span>
|
||
<span id="cb367-4"><a href="#cb367-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Name too long"</span>]</span>
|
||
<span id="cb367-5"><a href="#cb367-5" aria-hidden="true" tabindex="-1"></a>birthday <span class="st">"Yog-sothoth"</span> <span class="dv">10000</span></span>
|
||
<span id="cb367-6"><a href="#cb367-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Name too long"</span>,<span class="st">"Too old"</span>]</span></code></pre></div>
|
||
<p>Oh right, here are the <code>Functor</code> and
|
||
<code>Applicative</code> instances for <code>Validation</code>:</p>
|
||
<div class="sourceCode" id="cb368"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb368-1"><a href="#cb368-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Functor</span> <span class="dt">Validation</span> <span class="kw">where</span></span>
|
||
<span id="cb368-2"><a href="#cb368-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> f (<span class="dt">Ok</span> x) <span class="ot">=</span> <span class="dt">Ok</span> (f x)</span>
|
||
<span id="cb368-3"><a href="#cb368-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">fmap</span> _ (<span class="dt">Errors</span> e) <span class="ot">=</span> <span class="dt">Errors</span> e</span>
|
||
<span id="cb368-4"><a href="#cb368-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb368-5"><a href="#cb368-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Applicative</span> <span class="dt">Validation</span> <span class="kw">where</span></span>
|
||
<span id="cb368-6"><a href="#cb368-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">pure</span> x <span class="ot">=</span> <span class="dt">Ok</span> x</span>
|
||
<span id="cb368-7"><a href="#cb368-7" aria-hidden="true" tabindex="-1"></a> liftA2 f (<span class="dt">Ok</span> x) (<span class="dt">Ok</span> y) <span class="ot">=</span> <span class="dt">Ok</span> (f x y)</span>
|
||
<span id="cb368-8"><a href="#cb368-8" aria-hidden="true" tabindex="-1"></a> liftA2 f (<span class="dt">Errors</span> e1) (<span class="dt">Ok</span> y) <span class="ot">=</span> <span class="dt">Errors</span> e1</span>
|
||
<span id="cb368-9"><a href="#cb368-9" aria-hidden="true" tabindex="-1"></a> liftA2 f (<span class="dt">Ok</span> x) (<span class="dt">Errors</span> e2) <span class="ot">=</span> <span class="dt">Errors</span> e2</span>
|
||
<span id="cb368-10"><a href="#cb368-10" aria-hidden="true" tabindex="-1"></a> liftA2 f (<span class="dt">Errors</span> e1) (<span class="dt">Errors</span> e2) <span class="ot">=</span> <span class="dt">Errors</span> (e1<span class="op">++</span>e2)</span></code></pre></div>
|
||
<p>The definition of <code>liftA2</code> for <code>Validation</code>
|
||
shows that the errors are collected together left-to-right. This can be
|
||
seen in the example above where the expression
|
||
<code>liftA2 congratulate checkedName checkedAge</code> outputs the
|
||
error (<code>"Name too long"</code>) from <code>checkedName</code>
|
||
first, and the error (<code>"Too old"</code>) from
|
||
<code>checkedAge</code> last.</p>
|
||
<!-- TODO other applicatives: IO, ? -->
|
||
<h2 data-number="15.5" id="validating-lists-traverse"><span
|
||
class="header-section-number">15.5</span> Validating Lists:
|
||
<code>traverse</code></h2>
|
||
<p>So far we’ve dealt with fixed-size things and Applicatives: we’ve
|
||
applied a function of two or three arguments to some things. What if we
|
||
have an arbitrary amount of inputs? What if we need to validate a
|
||
list?</p>
|
||
<p>Let’s look at some ways to implement a function like this:</p>
|
||
<div class="sourceCode" id="cb369"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb369-1"><a href="#cb369-1" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb369-2"><a href="#cb369-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb369-3"><a href="#cb369-3" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb369-4"><a href="#cb369-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not positive: -4"</span>]</span>
|
||
<span id="cb369-5"><a href="#cb369-5" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb369-6"><a href="#cb369-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not positive: -2"</span>,<span class="st">"Not positive: -4"</span>]</span></code></pre></div>
|
||
<p>As always, when working with lists, pattern matching and recursion
|
||
are usually the way to go. Here’s a recursive solution:</p>
|
||
<div class="sourceCode" id="cb370"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb370-1"><a href="#cb370-1" aria-hidden="true" tabindex="-1"></a><span class="ot">allPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Validation</span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb370-2"><a href="#cb370-2" aria-hidden="true" tabindex="-1"></a>allPositive [] <span class="ot">=</span> <span class="dt">Ok</span> []</span>
|
||
<span id="cb370-3"><a href="#cb370-3" aria-hidden="true" tabindex="-1"></a>allPositive (x<span class="op">:</span>xs) <span class="ot">=</span> liftA2 (<span class="op">:</span>) checkThis checkRest</span>
|
||
<span id="cb370-4"><a href="#cb370-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> checkThis <span class="ot">=</span> check (x<span class="op">>=</span><span class="dv">0</span>) (<span class="st">"Not positive: "</span><span class="op">++</span><span class="fu">show</span> x) x</span>
|
||
<span id="cb370-5"><a href="#cb370-5" aria-hidden="true" tabindex="-1"></a> checkRest <span class="ot">=</span> allPositive xs</span></code></pre></div>
|
||
<p>It’s a bit of a chore to always spell out a recursion like this. If
|
||
we were working in a <code>Monad</code> we could just use a helper like
|
||
<code>mapM</code>:</p>
|
||
<div class="sourceCode" id="cb371"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb371-1"><a href="#cb371-1" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span> (\x <span class="ot">-></span> <span class="kw">if</span> x<span class="op">>=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <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>
|
||
<span id="cb371-2"><a href="#cb371-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb371-3"><a href="#cb371-3" aria-hidden="true" tabindex="-1"></a><span class="fu">mapM</span> (\x <span class="ot">-></span> <span class="kw">if</span> x<span class="op">>=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <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="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb371-4"><a href="#cb371-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>The equivalent of <code>mapM</code> for <code>Applicative</code> is
|
||
called <code>traverse</code>. It’s a member of the type class
|
||
<code>Traversable</code>:</p>
|
||
<div class="sourceCode" id="cb372"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb372-1"><a href="#cb372-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span><span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=></span> (a <span class="ot">-></span> f b) <span class="ot">-></span> t a <span class="ot">-></span> f (t b)</span></code></pre></div>
|
||
<p>That’s one heck of a type signature, so let’s simplify it a bit.
|
||
Lists are <code>Traversable</code>, so we can specialize this type
|
||
into:</p>
|
||
<div class="sourceCode" id="cb373"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb373-1"><a href="#cb373-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span><span class="ot"> ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> (a <span class="ot">-></span> f b) <span class="ot">-></span> [a] <span class="ot">-></span> f [b]</span></code></pre></div>
|
||
<p>That looks like what we need! For Applicatives that are also Monads,
|
||
<code>traverse</code> is just another name for <code>mapM</code>:</p>
|
||
<div class="sourceCode" id="cb374"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb374-1"><a href="#cb374-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> (\x <span class="ot">-></span> <span class="kw">if</span> x<span class="op">>=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <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>
|
||
<span id="cb374-2"><a href="#cb374-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb374-3"><a href="#cb374-3" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> (\x <span class="ot">-></span> <span class="kw">if</span> x<span class="op">>=</span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> x <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="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb374-4"><a href="#cb374-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>But for our <code>Validation</code>, which isn’t a
|
||
<code>Monad</code>, <code>traverse</code> is exactly what we want:</p>
|
||
<div class="sourceCode" id="cb375"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb375-1"><a href="#cb375-1" aria-hidden="true" tabindex="-1"></a><span class="ot">allPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Validation</span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb375-2"><a href="#cb375-2" aria-hidden="true" tabindex="-1"></a>allPositive xs <span class="ot">=</span> <span class="fu">traverse</span> checkNumber xs</span>
|
||
<span id="cb375-3"><a href="#cb375-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> checkNumber x <span class="ot">=</span> check (x<span class="op">>=</span><span class="dv">0</span>) (<span class="st">"Not positive: "</span><span class="op">++</span><span class="fu">show</span> x) x</span></code></pre></div>
|
||
<div class="sourceCode" id="cb376"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb376-1"><a href="#cb376-1" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb376-2"><a href="#cb376-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb376-3"><a href="#cb376-3" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb376-4"><a href="#cb376-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not positive: -4"</span>]</span>
|
||
<span id="cb376-5"><a href="#cb376-5" aria-hidden="true" tabindex="-1"></a>allPositive [<span class="dv">1</span>,<span class="op">-</span><span class="dv">2</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb376-6"><a href="#cb376-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not positive: -2"</span>,<span class="st">"Not positive: -4"</span>]</span></code></pre></div>
|
||
<p>Note how <code>traverse</code> for <code>Validation</code> collects
|
||
all the errors together, in the order they occur in the original
|
||
list.</p>
|
||
<p>PS. In fact, <code>Validation</code> is one of the few examples of an
|
||
<code>Applicative</code> that can’t be a <code>Monad</code>. Can you
|
||
figure out why?</p>
|
||
<!-- TODO `traverse_`? -->
|
||
<h2 data-number="15.6" id="sidenote-traversable"><span
|
||
class="header-section-number">15.6</span> Sidenote:
|
||
<code>Traversable</code></h2>
|
||
<p>So what things are <code>Traversable</code>? Many familiar
|
||
structures. Here are some examples:</p>
|
||
<div class="sourceCode" id="cb377"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb377-1"><a href="#cb377-1" aria-hidden="true" tabindex="-1"></a><span class="ot">decrease ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span></span>
|
||
<span id="cb377-2"><a href="#cb377-2" aria-hidden="true" tabindex="-1"></a>decrease i <span class="ot">=</span> <span class="kw">if</span> i<span class="op">></span><span class="dv">0</span> <span class="kw">then</span> <span class="dt">Just</span> (i<span class="op">-</span><span class="dv">1</span>) <span class="kw">else</span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb378"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb378-1"><a href="#cb378-1" aria-hidden="true" tabindex="-1"></a><span class="co">-- Lists are Traversable</span></span>
|
||
<span id="cb378-2"><a href="#cb378-2" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="dt">Just</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb378-3"><a href="#cb378-3" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb378-4"><a href="#cb378-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb378-5"><a href="#cb378-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Arrays are Traversable</span></span>
|
||
<span id="cb378-6"><a href="#cb378-6" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (array (<span class="dv">1</span>,<span class="dv">3</span>) [(<span class="dv">1</span>,<span class="dv">10</span>),(<span class="dv">2</span>,<span class="dv">11</span>),(<span class="dv">3</span>,<span class="dv">12</span>)])</span>
|
||
<span id="cb378-7"><a href="#cb378-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> (array (<span class="dv">1</span>,<span class="dv">3</span>) [(<span class="dv">1</span>,<span class="dv">9</span>),(<span class="dv">2</span>,<span class="dv">10</span>),(<span class="dv">3</span>,<span class="dv">11</span>)])</span>
|
||
<span id="cb378-8"><a href="#cb378-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb378-9"><a href="#cb378-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- Maps are Traversable</span></span>
|
||
<span id="cb378-10"><a href="#cb378-10" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (M.fromList [(<span class="st">"a"</span>,<span class="dv">1</span>),(<span class="st">"b"</span>,<span class="dv">2</span>)])</span>
|
||
<span id="cb378-11"><a href="#cb378-11" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Just</span> (M.fromList [(<span class="st">"a"</span>,<span class="dv">0</span>),(<span class="st">"b"</span>,<span class="dv">1</span>)])</span>
|
||
<span id="cb378-12"><a href="#cb378-12" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (M.fromList [(<span class="st">"a"</span>,<span class="dv">1</span>),(<span class="st">"b"</span>,<span class="dv">0</span>)])</span>
|
||
<span id="cb378-13"><a href="#cb378-13" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb378-14"><a href="#cb378-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb378-15"><a href="#cb378-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- Either is Traversable</span></span>
|
||
<span id="cb378-16"><a href="#cb378-16" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (<span class="dt">Left</span> <span class="st">"abc"</span>) <span class="op">==></span> <span class="dt">Just</span> (<span class="dt">Left</span> <span class="st">"abc"</span>)</span>
|
||
<span id="cb378-17"><a href="#cb378-17" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (<span class="dt">Right</span> <span class="dv">3</span>) <span class="op">==></span> <span class="dt">Just</span> (<span class="dt">Right</span> <span class="dv">2</span>)</span>
|
||
<span id="cb378-18"><a href="#cb378-18" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span> decrease (<span class="dt">Right</span> <span class="dv">0</span>) <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>So <code>Traversable</code> is a type class for all sorts of
|
||
containers, kind of like <code>Foldable</code>. Indeed, if you look at
|
||
the definition, <code>Traversable</code> is a subclass of
|
||
<code>Foldable</code>. It also turns out that <code>traverse</code> and
|
||
<code>mapM</code> are methods of the class!</p>
|
||
<div class="sourceCode" id="cb379"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb379-1"><a href="#cb379-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> (<span class="dt">Functor</span> t, <span class="dt">Foldable</span> t) <span class="ot">=></span> <span class="dt">Traversable</span> t <span class="kw">where</span></span>
|
||
<span id="cb379-2"><a href="#cb379-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> traverse ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> (a <span class="ot">-></span> f b) <span class="ot">-></span> t a <span class="ot">-></span> f (t b)</span>
|
||
<span id="cb379-3"><a href="#cb379-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> mapM ::</span> <span class="dt">Monad</span> m <span class="ot">=></span> (a <span class="ot">-></span> m b) <span class="ot">-></span> t a <span class="ot">-></span> m (t b)</span></code></pre></div>
|
||
<p>It can be hard to keep the types straight here. Let’s go back to the
|
||
type of <code>traverse</code>:</p>
|
||
<div class="sourceCode" id="cb380"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb380-1"><a href="#cb380-1" aria-hidden="true" tabindex="-1"></a><span class="fu">traverse</span><span class="ot"> ::</span> (<span class="dt">Traversable</span> t, <span class="dt">Applicative</span> f) <span class="ot">=></span> (a <span class="ot">-></span> f b) <span class="ot">-></span> t a <span class="ot">-></span> f (t b)</span></code></pre></div>
|
||
<p>Here we have two functors: <code>t</code> and <code>f</code>. The
|
||
<code>t</code> functor is also a <code>Foldable</code> and a
|
||
<code>Traversable</code> and the <code>f</code> functor is also an
|
||
<code>Applicative</code>. The <code>traverse</code> function lets us run
|
||
<code>f</code>-operations inside a <code>t</code>-container.</p>
|
||
<p>Don’t worry if that feels abstract. In practice, you pretty much
|
||
always use <code>traverse</code> on lists.</p>
|
||
<h2 data-number="15.7" id="dealing-with-failure-alternative"><span
|
||
class="header-section-number">15.7</span> Dealing with Failure:
|
||
<code>Alternative</code></h2>
|
||
<p>If you play around with applicatives a bit you’ll start to notice
|
||
some limits to their power. For example, when writing parsers like we
|
||
did in the <code>parseMoney</code> example, it would be nice to be able
|
||
to try a couple of different parsers and take any non-failure result.
|
||
This is easy enough to write for a concrete Applicative like
|
||
<code>Maybe</code>, as can be seen below.</p>
|
||
<div class="sourceCode" id="cb381"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb381-1"><a href="#cb381-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Answer</span> <span class="ot">=</span> <span class="dt">Yes</span> <span class="op">|</span> <span class="dt">No</span></span>
|
||
<span id="cb381-2"><a href="#cb381-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb381-3"><a href="#cb381-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-4"><a href="#cb381-4" aria-hidden="true" tabindex="-1"></a><span class="ot">parseYes ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Answer</span></span>
|
||
<span id="cb381-5"><a href="#cb381-5" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"y"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb381-6"><a href="#cb381-6" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"yes"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb381-7"><a href="#cb381-7" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"maybe"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb381-8"><a href="#cb381-8" aria-hidden="true" tabindex="-1"></a>parseYes _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb381-9"><a href="#cb381-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-10"><a href="#cb381-10" aria-hidden="true" tabindex="-1"></a><span class="ot">parseNo ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Answer</span></span>
|
||
<span id="cb381-11"><a href="#cb381-11" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"n"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">No</span></span>
|
||
<span id="cb381-12"><a href="#cb381-12" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"no"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">No</span></span>
|
||
<span id="cb381-13"><a href="#cb381-13" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"maybe"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="dt">No</span></span>
|
||
<span id="cb381-14"><a href="#cb381-14" aria-hidden="true" tabindex="-1"></a>parseNo _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb381-15"><a href="#cb381-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-16"><a href="#cb381-16" aria-hidden="true" tabindex="-1"></a><span class="ot">eitherOf ::</span> <span class="dt">Maybe</span> x <span class="ot">-></span> <span class="dt">Maybe</span> x <span class="ot">-></span> <span class="dt">Maybe</span> x</span>
|
||
<span id="cb381-17"><a href="#cb381-17" aria-hidden="true" tabindex="-1"></a>eitherOf (<span class="dt">Just</span> x) _ <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb381-18"><a href="#cb381-18" aria-hidden="true" tabindex="-1"></a>eitherOf <span class="dt">Nothing</span> mx <span class="ot">=</span> mx</span>
|
||
<span id="cb381-19"><a href="#cb381-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-20"><a href="#cb381-20" aria-hidden="true" tabindex="-1"></a><span class="ot">parseAnswer ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Answer</span></span>
|
||
<span id="cb381-21"><a href="#cb381-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- prefer positive answers!</span></span>
|
||
<span id="cb381-22"><a href="#cb381-22" aria-hidden="true" tabindex="-1"></a>parseAnswer s <span class="ot">=</span> eitherOf (parseYes s) (parseNo s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb382"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb382-1"><a href="#cb382-1" aria-hidden="true" tabindex="-1"></a>parseAnswer <span class="st">"yes"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb382-2"><a href="#cb382-2" aria-hidden="true" tabindex="-1"></a>parseAnswer <span class="st">"y"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb382-3"><a href="#cb382-3" aria-hidden="true" tabindex="-1"></a>parseAnswer <span class="st">"n"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">No</span></span>
|
||
<span id="cb382-4"><a href="#cb382-4" aria-hidden="true" tabindex="-1"></a>parseAnswer <span class="st">"maybe"</span> <span class="op">==></span> <span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb382-5"><a href="#cb382-5" aria-hidden="true" tabindex="-1"></a>parseAnswer <span class="st">"x"</span> <span class="op">==></span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>How could we generalize <code>eitherOf</code>? We can’t give it the
|
||
type <code>Applicative f => f x -> f x -> f x</code> because
|
||
then the implementation would need to be effectively something like
|
||
<code>eitherOf a b = liftA2 something a b</code>, but then
|
||
<code>eitherOf Nothing (Just x)</code> would be <code>Nothing</code>
|
||
(since that’s how the Applicative instance works)!</p>
|
||
<p>It turns out we need a new type class: <code>Alternative</code>. An
|
||
Alternative adds two operations to Applicative: <code>empty</code> means
|
||
no results, and <code><|></code> means combining results.</p>
|
||
<div class="sourceCode" id="cb383"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb383-1"><a href="#cb383-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Applicative</span> f <span class="ot">=></span> <span class="dt">Alternative</span> f <span class="kw">where</span></span>
|
||
<span id="cb383-2"><a href="#cb383-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> empty ::</span> f a</span>
|
||
<span id="cb383-3"><a href="#cb383-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<|>) ::</span> f a <span class="ot">-></span> f a <span class="ot">-></span> f a</span>
|
||
<span id="cb383-4"><a href="#cb383-4" aria-hidden="true" tabindex="-1"></a> <span class="co">-- some other operations omitted</span></span></code></pre></div>
|
||
<p>Now we can rewrite our parsing code using general operations:</p>
|
||
<div class="sourceCode" id="cb384"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb384-1"><a href="#cb384-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Answer</span> <span class="ot">=</span> <span class="dt">Yes</span> <span class="op">|</span> <span class="dt">No</span></span>
|
||
<span id="cb384-2"><a href="#cb384-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb384-3"><a href="#cb384-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb384-4"><a href="#cb384-4" aria-hidden="true" tabindex="-1"></a><span class="ot">parseYes ::</span> <span class="dt">Alternative</span> f <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> f <span class="dt">Answer</span></span>
|
||
<span id="cb384-5"><a href="#cb384-5" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"y"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">Yes</span></span>
|
||
<span id="cb384-6"><a href="#cb384-6" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"yes"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">Yes</span></span>
|
||
<span id="cb384-7"><a href="#cb384-7" aria-hidden="true" tabindex="-1"></a>parseYes <span class="st">"maybe"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">Yes</span></span>
|
||
<span id="cb384-8"><a href="#cb384-8" aria-hidden="true" tabindex="-1"></a>parseYes _ <span class="ot">=</span> empty</span>
|
||
<span id="cb384-9"><a href="#cb384-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb384-10"><a href="#cb384-10" aria-hidden="true" tabindex="-1"></a><span class="ot">parseNo ::</span> <span class="dt">Alternative</span> f <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> f <span class="dt">Answer</span></span>
|
||
<span id="cb384-11"><a href="#cb384-11" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"n"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">No</span></span>
|
||
<span id="cb384-12"><a href="#cb384-12" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"no"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">No</span></span>
|
||
<span id="cb384-13"><a href="#cb384-13" aria-hidden="true" tabindex="-1"></a>parseNo <span class="st">"maybe"</span> <span class="ot">=</span> <span class="fu">pure</span> <span class="dt">No</span></span>
|
||
<span id="cb384-14"><a href="#cb384-14" aria-hidden="true" tabindex="-1"></a>parseNo _ <span class="ot">=</span> empty</span>
|
||
<span id="cb384-15"><a href="#cb384-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb384-16"><a href="#cb384-16" aria-hidden="true" tabindex="-1"></a><span class="ot">parseAnswer ::</span> <span class="dt">Alternative</span> f <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> f <span class="dt">Answer</span></span>
|
||
<span id="cb384-17"><a href="#cb384-17" aria-hidden="true" tabindex="-1"></a>parseAnswer s <span class="ot">=</span> parseYes s <span class="op"><|></span> parseNo s</span></code></pre></div>
|
||
<p>We can also pick which <code>Alternative</code> we run our parser in
|
||
to get different behaviours. <code>Maybe</code> gives us only one
|
||
result, while <code>[]</code> gives us all possible results.</p>
|
||
<div class="sourceCode" id="cb385"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb385-1"><a href="#cb385-1" aria-hidden="true" tabindex="-1"></a><span class="op">></span> parseAnswer <span class="st">"yes"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></span>
|
||
<span id="cb385-2"><a href="#cb385-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb385-3"><a href="#cb385-3" aria-hidden="true" tabindex="-1"></a><span class="op">></span> parseAnswer <span class="st">"maybe"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Answer</span></span>
|
||
<span id="cb385-4"><a href="#cb385-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dt">Yes</span></span>
|
||
<span id="cb385-5"><a href="#cb385-5" aria-hidden="true" tabindex="-1"></a><span class="op">></span> parseAnswer <span class="st">"yes"</span><span class="ot"> ::</span> [<span class="dt">Answer</span>]</span>
|
||
<span id="cb385-6"><a href="#cb385-6" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Yes</span>]</span>
|
||
<span id="cb385-7"><a href="#cb385-7" aria-hidden="true" tabindex="-1"></a><span class="op">></span> parseAnswer <span class="st">"maybe"</span><span class="ot"> ::</span> [<span class="dt">Answer</span>]</span>
|
||
<span id="cb385-8"><a href="#cb385-8" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Yes</span>,<span class="dt">No</span>]</span></code></pre></div>
|
||
<p>The <code>Alternative</code> instances for <code>[]</code> and
|
||
<code>Maybe</code> are unsurprising:</p>
|
||
<div class="sourceCode" id="cb386"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb386-1"><a href="#cb386-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Alternative</span> [] <span class="kw">where</span></span>
|
||
<span id="cb386-2"><a href="#cb386-2" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> []</span>
|
||
<span id="cb386-3"><a href="#cb386-3" aria-hidden="true" tabindex="-1"></a> (<span class="op"><|></span>) <span class="ot">=</span> (<span class="op">++</span>)</span>
|
||
<span id="cb386-4"><a href="#cb386-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb386-5"><a href="#cb386-5" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Maybe</span> <span class="kw">where</span></span>
|
||
<span id="cb386-6"><a href="#cb386-6" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb386-7"><a href="#cb386-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> x <span class="op"><|></span> _ <span class="ot">=</span> <span class="dt">Just</span> x</span>
|
||
<span id="cb386-8"><a href="#cb386-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="op"><|></span> mx <span class="ot">=</span> mx</span></code></pre></div>
|
||
<p>The <code>Validation</code> type is also an <code>Alternative</code>.
|
||
The instance collects together all error messages, just like the
|
||
<code>Applicative</code> instance did.</p>
|
||
<div class="sourceCode" id="cb387"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb387-1"><a href="#cb387-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Alternative</span> <span class="dt">Validation</span> <span class="kw">where</span></span>
|
||
<span id="cb387-2"><a href="#cb387-2" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">Errors</span> []</span>
|
||
<span id="cb387-3"><a href="#cb387-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Ok</span> x <span class="op"><|></span> _ <span class="ot">=</span> <span class="dt">Ok</span> x</span>
|
||
<span id="cb387-4"><a href="#cb387-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Errors</span> e1 <span class="op"><|></span> <span class="dt">Ok</span> y <span class="ot">=</span> <span class="dt">Ok</span> y</span>
|
||
<span id="cb387-5"><a href="#cb387-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">Errors</span> e1 <span class="op"><|></span> <span class="dt">Errors</span> e2 <span class="ot">=</span> <span class="dt">Errors</span> (e1<span class="op">++</span>e2)</span></code></pre></div>
|
||
<p>Here’s a final example: validating contact information, which is
|
||
either a phone number or an email address.</p>
|
||
<div class="sourceCode" id="cb388"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb388-1"><a href="#cb388-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">ContactInfo</span> <span class="ot">=</span> <span class="dt">Email</span> <span class="dt">String</span> <span class="op">|</span> <span class="dt">Phone</span> <span class="dt">String</span></span>
|
||
<span id="cb388-2"><a href="#cb388-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb388-3"><a href="#cb388-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb388-4"><a href="#cb388-4" aria-hidden="true" tabindex="-1"></a><span class="ot">validateEmail ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></span>
|
||
<span id="cb388-5"><a href="#cb388-5" aria-hidden="true" tabindex="-1"></a>validateEmail s <span class="ot">=</span> check (<span class="fu">elem</span> <span class="ch">'@'</span> s) <span class="st">"Not an email: should contain a @"</span> (<span class="dt">Email</span> s)</span>
|
||
<span id="cb388-6"><a href="#cb388-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb388-7"><a href="#cb388-7" aria-hidden="true" tabindex="-1"></a><span class="ot">checkLength ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></span>
|
||
<span id="cb388-8"><a href="#cb388-8" aria-hidden="true" tabindex="-1"></a>checkLength s <span class="ot">=</span> check (<span class="fu">length</span> s <span class="op"><=</span> <span class="dv">10</span>) <span class="st">"Not a phone number: should be at most 10 digits"</span> (<span class="dt">Phone</span> s)</span>
|
||
<span id="cb388-9"><a href="#cb388-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb388-10"><a href="#cb388-10" aria-hidden="true" tabindex="-1"></a><span class="ot">checkDigits ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></span>
|
||
<span id="cb388-11"><a href="#cb388-11" aria-hidden="true" tabindex="-1"></a>checkDigits s <span class="ot">=</span> check (<span class="fu">all</span> <span class="fu">isDigit</span> s) <span class="st">"Not a phone number: should be all numbers"</span> (<span class="dt">Phone</span> s)</span>
|
||
<span id="cb388-12"><a href="#cb388-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb388-13"><a href="#cb388-13" aria-hidden="true" tabindex="-1"></a><span class="ot">validatePhone ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></span>
|
||
<span id="cb388-14"><a href="#cb388-14" aria-hidden="true" tabindex="-1"></a>validatePhone s <span class="ot">=</span> checkDigits s <span class="op">*></span> checkLength s</span>
|
||
<span id="cb388-15"><a href="#cb388-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb388-16"><a href="#cb388-16" aria-hidden="true" tabindex="-1"></a><span class="ot">validateContactInfo ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Validation</span> <span class="dt">ContactInfo</span></span>
|
||
<span id="cb388-17"><a href="#cb388-17" aria-hidden="true" tabindex="-1"></a>validateContactInfo s <span class="ot">=</span> validateEmail s <span class="op"><|></span> validatePhone s</span></code></pre></div>
|
||
<div class="sourceCode" id="cb389"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb389-1"><a href="#cb389-1" aria-hidden="true" tabindex="-1"></a>validateContactInfo <span class="st">"user@example.com"</span></span>
|
||
<span id="cb389-2"><a href="#cb389-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> (<span class="dt">Email</span> <span class="st">"user@example.com"</span>)</span>
|
||
<span id="cb389-3"><a href="#cb389-3" aria-hidden="true" tabindex="-1"></a>validateContactInfo <span class="st">"01234"</span></span>
|
||
<span id="cb389-4"><a href="#cb389-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Ok</span> (<span class="dt">Phone</span> <span class="st">"01234"</span>)</span>
|
||
<span id="cb389-5"><a href="#cb389-5" aria-hidden="true" tabindex="-1"></a>validateContactInfo <span class="st">"01234567890"</span></span>
|
||
<span id="cb389-6"><a href="#cb389-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not an email: should contain a @"</span>,<span class="st">"Not a phone number: should be at most 10 digits"</span>]</span>
|
||
<span id="cb389-7"><a href="#cb389-7" aria-hidden="true" tabindex="-1"></a>validateContactInfo <span class="st">"01234567890x"</span></span>
|
||
<span id="cb389-8"><a href="#cb389-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not an email: should contain a @"</span>,</span>
|
||
<span id="cb389-9"><a href="#cb389-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"Not a phone number: should be all numbers"</span>,</span>
|
||
<span id="cb389-10"><a href="#cb389-10" aria-hidden="true" tabindex="-1"></a> <span class="st">"Not a phone number: should be at most 10 digits"</span>]</span>
|
||
<span id="cb389-11"><a href="#cb389-11" aria-hidden="true" tabindex="-1"></a>validateContactInfo <span class="st">"x"</span></span>
|
||
<span id="cb389-12"><a href="#cb389-12" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Errors</span> [<span class="st">"Not an email: should contain a @"</span>,</span>
|
||
<span id="cb389-13"><a href="#cb389-13" aria-hidden="true" tabindex="-1"></a> <span class="st">"Not a phone number: should be all numbers"</span>]</span></code></pre></div>
|
||
<p>Note how here, just like in previous examples, the errors are
|
||
collected left-to-right: the errors from <code>validateEmail</code> come
|
||
before the errors from <code>validatePhone</code>. The error from
|
||
<code>checkDigits</code> comes before the error from
|
||
<code>checkLength</code>.</p>
|
||
<!--
|
||
TODO compare to `Monoid`?
|
||
|
||
TODO another example
|
||
|
||
TODO explain `some` and `many`
|
||
-->
|
||
<h2 data-number="15.8" id="sidenote-applicatives-in-context"><span
|
||
class="header-section-number">15.8</span> Sidenote: Applicatives in
|
||
Context</h2>
|
||
<h3 data-number="15.8.1" id="why-applicatives"><span
|
||
class="header-section-number">15.8.1</span> Why Applicatives?</h3>
|
||
<p>There are multiple reasons for learning Applicatives, even if they do
|
||
not provide any additional power over Monads. First off, as discussed in
|
||
Lecture 13, the GHC standard library nowadays makes Applicative
|
||
instances for all Monads compulsory. Thus a working Haskell programmer
|
||
is bound to see lots of Applicative instances.</p>
|
||
<p>Secondly, you’ll bump into Applicative operators a lot even in
|
||
Monadic code. Expressions like
|
||
<code>f <$> x <*> y <*> z</code> can be useful in many
|
||
Monadic contexts. Also, since the <code>Traversable</code> type class is
|
||
built in terms of <code>Applicative</code>, you’ll often use applicative
|
||
operations with it.</p>
|
||
<p>Thirdly, Applicatives are an excellent exercise in understanding
|
||
functional design patterns. They marry the Functor pattern with the
|
||
Monoid pattern, and Alternative brings in yet another Monoid-like
|
||
dimension. Being able to efficiently work with Applicatives will make
|
||
working with further abstractions like <em>monad transformers</em> or
|
||
<em>lenses</em> easier.</p>
|
||
<p>Lastly, there are a couple of types that are Applicatives but not
|
||
Monads. <code>Validation</code> is one example, and a very practical one
|
||
at that. Without understanding of Applicative, we’d have no way to
|
||
recognize and generalize operations over types like this. Another such
|
||
type is <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Control-Applicative.html#t:ZipList"><code>ZipList</code></a>.</p>
|
||
<h3 data-number="15.8.2" id="applicatives-in-the-wild"><span
|
||
class="header-section-number">15.8.2</span> Applicatives in the
|
||
Wild</h3>
|
||
<p>Even though we only looked at some very simple and concrete
|
||
Applicatives in this lecture, there are plenty of Haskell libraries that
|
||
use Applicatives for big things. Here are some examples.</p>
|
||
<p>The same sort of idea as our <code>Validation</code> Applicative has
|
||
been implemented in the <a
|
||
href="https://hackage.haskell.org/package/validation">validation</a> and
|
||
<a href="https://hackage.haskell.org/package/either">either</a>
|
||
libraries.</p>
|
||
<p>There are multiple parser libraries that use Applicatives. For
|
||
example, <a
|
||
href="https://hackage.haskell.org/package/regex-applicative">regex-applicative</a>,
|
||
<a
|
||
href="https://hackage.haskell.org/package/optparse-applicative">optparse-applicative</a>,
|
||
<a
|
||
href="https://cs-syd.eu/posts/2020-06-28-yamlparse-applicative">yamlparse-applicative</a>,
|
||
<a
|
||
href="https://hackage.haskell.org/package/json-stream">json-stream</a>,
|
||
and so on.</p>
|
||
<h3 data-number="15.8.3" id="monads-and-applicatives"><span
|
||
class="header-section-number">15.8.3</span> Monads and Applicatives</h3>
|
||
<p>So what’s the relationship between an Monad and an Applicative? If an
|
||
Applicative is also a Monad, the following laws hold:</p>
|
||
<div class="sourceCode" id="cb390"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb390-1"><a href="#cb390-1" aria-hidden="true" tabindex="-1"></a><span class="fu">pure</span> <span class="op">===</span> <span class="fu">return</span></span>
|
||
<span id="cb390-2"><a href="#cb390-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-3"><a href="#cb390-3" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> <span class="op">===</span> liftM</span>
|
||
<span id="cb390-4"><a href="#cb390-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-5"><a href="#cb390-5" aria-hidden="true" tabindex="-1"></a><span class="fu">fmap</span> f op <span class="op">===</span> <span class="kw">do</span> x <span class="ot"><-</span> op</span>
|
||
<span id="cb390-6"><a href="#cb390-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (f x)</span>
|
||
<span id="cb390-7"><a href="#cb390-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-8"><a href="#cb390-8" aria-hidden="true" tabindex="-1"></a>liftA2 <span class="op">===</span> liftM2</span>
|
||
<span id="cb390-9"><a href="#cb390-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-10"><a href="#cb390-10" aria-hidden="true" tabindex="-1"></a>liftA2 f op1 op2 <span class="op">===</span> <span class="kw">do</span> x <span class="ot"><-</span> op1</span>
|
||
<span id="cb390-11"><a href="#cb390-11" aria-hidden="true" tabindex="-1"></a> y <span class="ot"><-</span> op2</span>
|
||
<span id="cb390-12"><a href="#cb390-12" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (f x y)</span>
|
||
<span id="cb390-13"><a href="#cb390-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-14"><a href="#cb390-14" aria-hidden="true" tabindex="-1"></a>op1 <span class="op">*></span> op2 <span class="op">===</span> op1 <span class="op">>></span> op2</span>
|
||
<span id="cb390-15"><a href="#cb390-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb390-16"><a href="#cb390-16" aria-hidden="true" tabindex="-1"></a>op1 <span class="op"><*></span> op2 <span class="op">===</span> <span class="kw">do</span> f <span class="ot"><-</span> op1</span>
|
||
<span id="cb390-17"><a href="#cb390-17" aria-hidden="true" tabindex="-1"></a> x <span class="ot"><-</span> op2</span>
|
||
<span id="cb390-18"><a href="#cb390-18" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (f x)</span></code></pre></div>
|
||
<p>When working in a <code>Monad</code>, you can freely mix
|
||
<code>Applicative</code> and <code>Functor</code> with
|
||
<code>Monad</code> operations. As an example, let’s rewrite
|
||
<code>mapM</code> until it only uses applicative operations, and thus
|
||
get an implementation for <code>traverse</code>. This is our starting
|
||
point:</p>
|
||
<div class="sourceCode" id="cb391"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb391-1"><a href="#cb391-1" aria-hidden="true" tabindex="-1"></a>myMapM op [] <span class="ot">=</span> <span class="fu">return</span> []</span>
|
||
<span id="cb391-2"><a href="#cb391-2" aria-hidden="true" tabindex="-1"></a>myMapM op (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="kw">do</span> y <span class="ot"><-</span> op x</span>
|
||
<span id="cb391-3"><a href="#cb391-3" aria-hidden="true" tabindex="-1"></a> ys <span class="ot"><-</span> myMapM op xs</span>
|
||
<span id="cb391-4"><a href="#cb391-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (y<span class="op">:</span>ys)</span></code></pre></div>
|
||
<p>GHCi tells us it only works for Monads:</p>
|
||
<div class="sourceCode" id="cb392"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb392-1"><a href="#cb392-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t myMapM</span>
|
||
<span id="cb392-2"><a href="#cb392-2" aria-hidden="true" tabindex="-1"></a><span class="ot">myMapM ::</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></code></pre></div>
|
||
<p>Let’s apply the <code>pure === return</code> and the
|
||
<code>liftA2</code> laws from above:</p>
|
||
<div class="sourceCode" id="cb393"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb393-1"><a href="#cb393-1" aria-hidden="true" tabindex="-1"></a>myMapM op [] <span class="ot">=</span> <span class="fu">pure</span> []</span>
|
||
<span id="cb393-2"><a href="#cb393-2" aria-hidden="true" tabindex="-1"></a>myMapM op (x<span class="op">:</span>xs) <span class="ot">=</span> liftA2 (<span class="op">:</span>) (op x) (myMapM op xs)</span></code></pre></div>
|
||
<p>Ta-da! Now <code>myMapM</code> works for any
|
||
<code>Applicative</code>:</p>
|
||
<div class="sourceCode" id="cb394"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb394-1"><a href="#cb394-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t myMapM</span>
|
||
<span id="cb394-2"><a href="#cb394-2" aria-hidden="true" tabindex="-1"></a><span class="ot">myMapM ::</span> <span class="dt">Applicative</span> f <span class="ot">=></span> (a <span class="ot">-></span> f b) <span class="ot">-></span> [a] <span class="ot">-></span> f [b]</span></code></pre></div>
|
||
<h2 data-number="15.9" id="quiz-5"><span
|
||
class="header-section-number">15.9</span> Quiz</h2>
|
||
<p>What’s the type of <code>x</code> in
|
||
<code>liftA2 (&&) Nothing x</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Applicative f => f Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>Applicative Bool</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Maybe Bool</code>
|
||
</li>
|
||
</ol>
|
||
<p>How many elements does <code>liftA2 f xs ys</code> have when
|
||
<code>xs</code> and <code>ys</code> are lists?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>length xs + length ys</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>length xs * length ys</code>
|
||
</li>
|
||
<li>
|
||
<code>min (length xs) (length ys)</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of these expressions is equivalent to
|
||
<code>liftA2 f x y</code>? There might be multiple correct answers.</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>f <$> x <*> y</code>
|
||
</li>
|
||
<li>
|
||
<code>f <*> x <*> y</code>
|
||
</li>
|
||
<li>
|
||
<code>f <*> x <$> y</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>fmap f x <*> y</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>pure f <*> x <*> y</code>
|
||
</li>
|
||
</ol>
|
||
<p>If <code>f :: a -> Maybe b</code> and <code>xs :: [a]</code>,
|
||
which of these expressions has a type different from the others?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>fmap f xs</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>traverse f xs</code>
|
||
</li>
|
||
<li>
|
||
<code>map f xs</code>
|
||
</li>
|
||
</ol>
|
||
<p>For which <code>Applicative</code> do the expressions
|
||
<code>pure x <* pure y</code> and
|
||
<code>pure x <|> pure y</code> produce different results?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Maybe</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>[]</code>
|
||
</li>
|
||
<li>
|
||
<code>Validation</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="15.10" id="exercises-6"><span
|
||
class="header-section-number">15.10</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set15.hs">Set15</a></li>
|
||
</ul>
|
||
<h1 data-number="16" id="lecture-16-odds-and-ends"><span
|
||
class="header-section-number">16</span> Lecture 16: Odds and Ends</h1>
|
||
<p>This final lecture will go over some minor topics that didn’t fit in
|
||
anywhere else. You’ve finished all the hard parts of the course. Now
|
||
it’s time to sit back, relax, and enjoy some cool Haskell!</p>
|
||
<h2 data-number="16.1" id="testing-with-quickcheck"><span
|
||
class="header-section-number">16.1</span> Testing with QuickCheck</h2>
|
||
<p>One of the benefits of purity is that pure functions are easy to
|
||
test: you don’t need to set up any global state, you can just pass in
|
||
arguments and check that the result is ok. In this section, we’ll take a
|
||
quick tour of the <em>property-based testing</em> library QuickCheck,
|
||
which has also been used for checking that your answers to exercises are
|
||
right on this course!</p>
|
||
<p>Let’s look at testing a (faulty) implementation of
|
||
<code>reverse</code>. You can find this and the following examples in
|
||
the file <a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/QuickCheck.hs"><code>exercises/Examples/QuickCheck.hs</code></a>.</p>
|
||
<div class="sourceCode" id="cb395"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb395-1"><a href="#cb395-1" aria-hidden="true" tabindex="-1"></a><span class="ot">rev ::</span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb395-2"><a href="#cb395-2" aria-hidden="true" tabindex="-1"></a>rev (x<span class="op">:</span>y<span class="op">:</span>xs) <span class="ot">=</span> y<span class="op">:</span>x<span class="op">:</span>xs</span>
|
||
<span id="cb395-3"><a href="#cb395-3" aria-hidden="true" tabindex="-1"></a>rev xs <span class="ot">=</span> xs</span></code></pre></div>
|
||
<p>We can write an individual test case using the <code>===</code>
|
||
operator from QuickCheck:</p>
|
||
<div class="sourceCode" id="cb396"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb396-1"><a href="#cb396-1" aria-hidden="true" tabindex="-1"></a><span class="ot">(===) ::</span> (<span class="dt">Eq</span> a, <span class="dt">Show</span> a) <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Property</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb397"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb397-1"><a href="#cb397-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propRevSmall ::</span> <span class="dt">Property</span></span>
|
||
<span id="cb397-2"><a href="#cb397-2" aria-hidden="true" tabindex="-1"></a>propRevSmall <span class="ot">=</span> rev [<span class="dv">1</span>,<span class="dv">2</span>] <span class="op">===</span> [<span class="dv">2</span>,<span class="dv">1</span>]</span></code></pre></div>
|
||
<p>We can ask QuickCheck to run them in GHCi:</p>
|
||
<div class="sourceCode" id="cb398"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb398-1"><a href="#cb398-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propRevSmall</span>
|
||
<span id="cb398-2"><a href="#cb398-2" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">1</span> test<span class="op">.</span></span></code></pre></div>
|
||
<p>So far so good. However this isn’t really what QuickCheck was made
|
||
for. QuickCheck was designed for <em>property-based testing</em> where
|
||
you can state a property your code should have, and QuickCheck runs your
|
||
code with randomized inputs, checking the property every time. What
|
||
would be a simple property that a correct implementation of
|
||
<code>reverse</code> has? Reversing a list twice should certainly give
|
||
us back the same list. Let’s write it out:</p>
|
||
<div class="sourceCode" id="cb399"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb399-1"><a href="#cb399-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propRevTwice ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb399-2"><a href="#cb399-2" aria-hidden="true" tabindex="-1"></a>propRevTwice xs <span class="ot">=</span> rev (rev xs) <span class="op">===</span> xs</span></code></pre></div>
|
||
<p>Our <code>Property</code> has an argument, which means that
|
||
QuickCheck will generate random values and run the test. We can use the
|
||
<code>verboseCheck</code> function to see which values are run. We can
|
||
also give a parameter to the test ourselves if we wish to check a
|
||
specific value.</p>
|
||
<div class="sourceCode" id="cb400"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb400-1"><a href="#cb400-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propRevTwice</span>
|
||
<span id="cb400-2"><a href="#cb400-2" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">100</span> tests<span class="op">.</span></span>
|
||
<span id="cb400-3"><a href="#cb400-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> verboseCheck propRevTwice</span>
|
||
<span id="cb400-4"><a href="#cb400-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Passed</span><span class="op">:</span></span>
|
||
<span id="cb400-5"><a href="#cb400-5" aria-hidden="true" tabindex="-1"></a>[]</span>
|
||
<span id="cb400-6"><a href="#cb400-6" aria-hidden="true" tabindex="-1"></a>[] <span class="op">==</span> []</span>
|
||
<span id="cb400-7"><a href="#cb400-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb400-8"><a href="#cb400-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Passed</span><span class="op">:</span></span>
|
||
<span id="cb400-9"><a href="#cb400-9" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>]</span>
|
||
<span id="cb400-10"><a href="#cb400-10" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>] <span class="op">==</span> [<span class="dv">1</span>]</span>
|
||
<span id="cb400-11"><a href="#cb400-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb400-12"><a href="#cb400-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Passed</span><span class="op">:</span></span>
|
||
<span id="cb400-13"><a href="#cb400-13" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">2</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">1</span>]</span>
|
||
<span id="cb400-14"><a href="#cb400-14" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">2</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">1</span>] <span class="op">==</span> [<span class="op">-</span><span class="dv">2</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">1</span>]</span>
|
||
<span id="cb400-15"><a href="#cb400-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- lots of output</span></span>
|
||
<span id="cb400-16"><a href="#cb400-16" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">100</span> tests<span class="op">.</span></span>
|
||
<span id="cb400-17"><a href="#cb400-17" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck (propRevTwice [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>])</span>
|
||
<span id="cb400-18"><a href="#cb400-18" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">1</span> test<span class="op">.</span></span></code></pre></div>
|
||
<p>Even this property didn’t catch the bug in our implementation. Let’s
|
||
try another one. Here’s a property about how <code>rev (xs ++ ys)</code>
|
||
behaves. You might want to take a moment to convince yourself that it
|
||
should hold for a correct <code>rev</code> function.</p>
|
||
<div class="sourceCode" id="cb401"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb401-1"><a href="#cb401-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propRevTwo ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb401-2"><a href="#cb401-2" aria-hidden="true" tabindex="-1"></a>propRevTwo xs ys <span class="ot">=</span> rev (xs <span class="op">++</span> ys) <span class="op">===</span> rev ys <span class="op">++</span> rev xs</span></code></pre></div>
|
||
<p>Let’s see if it holds for our implementation:</p>
|
||
<div class="sourceCode" id="cb402"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb402-1"><a href="#cb402-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propRevTwo</span>
|
||
<span id="cb402-2"><a href="#cb402-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Falsified</span> (after <span class="dv">5</span> tests <span class="fu">and</span> <span class="dv">3</span> shrinks)<span class="op">:</span></span>
|
||
<span id="cb402-3"><a href="#cb402-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb402-4"><a href="#cb402-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>]</span>
|
||
<span id="cb402-5"><a href="#cb402-5" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span></code></pre></div>
|
||
<p>Finally, a failure! There’s a bit to unpack here. First off,
|
||
QuickCheck tells us the arguments with which the property failed: they
|
||
are <code>[0,0]</code> and <code>[1]</code>. We can check this
|
||
ourselves:</p>
|
||
<div class="sourceCode" id="cb403"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb403-1"><a href="#cb403-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck (propRevTwo [<span class="dv">0</span>,<span class="dv">0</span>] [<span class="dv">1</span>])</span>
|
||
<span id="cb403-2"><a href="#cb403-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Falsified</span> (after <span class="dv">1</span> test)<span class="op">:</span></span>
|
||
<span id="cb403-3"><a href="#cb403-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span></code></pre></div>
|
||
<p>Next up, what does “after 5 tests and 3 shrinks” mean? One of the
|
||
cool things about QuickCheck is that when it finds a failure, it tries
|
||
some related values in order to find a nicer, smaller failure. We can
|
||
see this in action with <code>verboseShrinking</code>, which prints out
|
||
all the failures QuickCheck goes through:</p>
|
||
<div class="sourceCode" id="cb404"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb404-1"><a href="#cb404-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck (verboseShrinking propRevTwo)</span>
|
||
<span id="cb404-2"><a href="#cb404-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-3"><a href="#cb404-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">4</span>,<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb404-4"><a href="#cb404-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-5"><a href="#cb404-5" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">4</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-6"><a href="#cb404-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-7"><a href="#cb404-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-8"><a href="#cb404-8" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb404-9"><a href="#cb404-9" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-10"><a href="#cb404-10" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">4</span>,<span class="op">-</span><span class="dv">1</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="op">-</span><span class="dv">1</span>]</span>
|
||
<span id="cb404-11"><a href="#cb404-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-12"><a href="#cb404-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-13"><a href="#cb404-13" aria-hidden="true" tabindex="-1"></a>[<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb404-14"><a href="#cb404-14" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-15"><a href="#cb404-15" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>,<span class="op">-</span><span class="dv">4</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>]</span>
|
||
<span id="cb404-16"><a href="#cb404-16" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-17"><a href="#cb404-17" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-18"><a href="#cb404-18" aria-hidden="true" tabindex="-1"></a>[<span class="dv">4</span>]</span>
|
||
<span id="cb404-19"><a href="#cb404-19" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-20"><a href="#cb404-20" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">4</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-21"><a href="#cb404-21" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-22"><a href="#cb404-22" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-23"><a href="#cb404-23" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>]</span>
|
||
<span id="cb404-24"><a href="#cb404-24" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-25"><a href="#cb404-25" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">1</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb404-26"><a href="#cb404-26" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-27"><a href="#cb404-27" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-28"><a href="#cb404-28" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>]</span>
|
||
<span id="cb404-29"><a href="#cb404-29" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb404-30"><a href="#cb404-30" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">4</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">4</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb404-31"><a href="#cb404-31" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-32"><a href="#cb404-32" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-33"><a href="#cb404-33" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>]</span>
|
||
<span id="cb404-34"><a href="#cb404-34" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb404-35"><a href="#cb404-35" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">2</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">2</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb404-36"><a href="#cb404-36" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb404-37"><a href="#cb404-37" aria-hidden="true" tabindex="-1"></a><span class="dt">Failed</span><span class="op">:</span></span>
|
||
<span id="cb404-38"><a href="#cb404-38" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>]</span>
|
||
<span id="cb404-39"><a href="#cb404-39" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb404-40"><a href="#cb404-40" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span></code></pre></div>
|
||
<p>QuickCheck went down from a counterexample of
|
||
<code>[4,1,-1,4,4]</code> all the way to <code>[1,0,0]</code>. Pretty
|
||
sweet!</p>
|
||
<h3 data-number="16.1.1" id="modifiers"><span
|
||
class="header-section-number">16.1.1</span> Modifiers</h3>
|
||
<p>Sometimes you need to limit the values QuickCheck generates. Your
|
||
function might not work on all inputs, for instance? Let’s try writing a
|
||
test for <code>last</code>.</p>
|
||
<div class="sourceCode" id="cb405"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb405-1"><a href="#cb405-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propLast ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb405-2"><a href="#cb405-2" aria-hidden="true" tabindex="-1"></a>propLast xs <span class="ot">=</span> <span class="fu">last</span> xs <span class="op">===</span> <span class="fu">head</span> (<span class="fu">reverse</span> xs)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb406"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb406-1"><a href="#cb406-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propLast</span>
|
||
<span id="cb406-2"><a href="#cb406-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Exception</span><span class="op">:</span> <span class="dt">'Prelude</span><span class="op">.</span><span class="fu">last</span><span class="op">:</span> empty list' (after <span class="dv">1</span> test)<span class="op">:</span></span>
|
||
<span id="cb406-3"><a href="#cb406-3" aria-hidden="true" tabindex="-1"></a>[]</span></code></pre></div>
|
||
<p>In this case, we can fix the test just by switching to another input
|
||
type. QuickCheck defines the <code>NonEmptyList</code> type (not to be
|
||
confused with <code>Data.List.NonEmpty</code>!), which is just a wrapper
|
||
for a normal list. However, when generating values of
|
||
<code>NonEmptyList</code>, QuickCheck won’t generate empty lists.</p>
|
||
<div class="sourceCode" id="cb407"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb407-1"><a href="#cb407-1" aria-hidden="true" tabindex="-1"></a><span class="kw">newtype</span> <span class="dt">NonEmptyList</span> a <span class="ot">=</span> <span class="dt">NonEmpty</span> [a]</span></code></pre></div>
|
||
<div class="sourceCode" id="cb408"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb408-1"><a href="#cb408-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propLastFixed ::</span> <span class="dt">NonEmptyList</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb408-2"><a href="#cb408-2" aria-hidden="true" tabindex="-1"></a>propLastFixed (<span class="dt">NonEmpty</span> xs) <span class="ot">=</span> <span class="fu">last</span> xs <span class="op">===</span> <span class="fu">head</span> (<span class="fu">reverse</span> xs)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb409"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb409-1"><a href="#cb409-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propLastFixed</span>
|
||
<span id="cb409-2"><a href="#cb409-2" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">100</span> tests<span class="op">.</span></span></code></pre></div>
|
||
<p>There are <a
|
||
href="https://hackage.haskell.org/package/QuickCheck-2.14.3/docs/Test-QuickCheck.html#g:16">other
|
||
modifiers</a> like this, for example <code>Positive</code> for positive
|
||
numbers, <code>NonNegative</code> for non-negative numbers, or
|
||
<code>SortedList</code> for a sorted list. Here’s an example of a more
|
||
complex test. We check that the nth element of <code>cycle xs</code> is
|
||
correct. Both of the modifiers are needed, since <code>!!</code> doesn’t
|
||
work with negative inputs, and <code>cycle []</code> is an error.</p>
|
||
<div class="sourceCode" id="cb410"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb410-1"><a href="#cb410-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propCycle ::</span> <span class="dt">NonEmptyList</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">NonNegative</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb410-2"><a href="#cb410-2" aria-hidden="true" tabindex="-1"></a>propCycle (<span class="dt">NonEmpty</span> xs) (<span class="dt">NonNegative</span> n) <span class="ot">=</span></span>
|
||
<span id="cb410-3"><a href="#cb410-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">cycle</span> xs <span class="op">!!</span> n <span class="op">===</span> xs <span class="op">!!</span> (<span class="fu">mod</span> n (<span class="fu">length</span> xs))</span></code></pre></div>
|
||
<h3 data-number="16.1.2" id="generators-and-forall"><span
|
||
class="header-section-number">16.1.2</span> Generators and
|
||
<code>forAll</code></h3>
|
||
<p>Sometimes we need to limit the range of inputs to a test even
|
||
further. As a simple example, here’s a test that
|
||
<code>Data.Char.toUpper</code> changes the character passed to it:</p>
|
||
<div class="sourceCode" id="cb411"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb411-1"><a href="#cb411-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propToUpperChanges ::</span> <span class="dt">Char</span> <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb411-2"><a href="#cb411-2" aria-hidden="true" tabindex="-1"></a>propToUpperChanges c <span class="ot">=</span> <span class="fu">toUpper</span> c <span class="op">=/=</span> c</span></code></pre></div>
|
||
<div class="sourceCode" id="cb412"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb412-1"><a href="#cb412-1" aria-hidden="true" tabindex="-1"></a>quickCheck propToUpperChanges</span>
|
||
<span id="cb412-2"><a href="#cb412-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Falsified</span> (after <span class="dv">1</span> test <span class="fu">and</span> <span class="dv">1</span> shrink)<span class="op">:</span></span>
|
||
<span id="cb412-3"><a href="#cb412-3" aria-hidden="true" tabindex="-1"></a><span class="ch">'A'</span></span>
|
||
<span id="cb412-4"><a href="#cb412-4" aria-hidden="true" tabindex="-1"></a><span class="ch">'A'</span> <span class="op">==</span> <span class="ch">'A'</span></span></code></pre></div>
|
||
<p>Of course, it only changes <em>lowercase letters</em>. How can we
|
||
write a test for that? There is no <code>Lowercase</code> modifier
|
||
available that would work like <code>Positive</code> or
|
||
<code>NonEmptyList</code>. We need to fall back to explicit generation
|
||
of values using <code>forAll</code>:</p>
|
||
<div class="sourceCode" id="cb413"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb413-1"><a href="#cb413-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propToUpperChangesLetter ::</span> <span class="dt">Property</span></span>
|
||
<span id="cb413-2"><a href="#cb413-2" aria-hidden="true" tabindex="-1"></a>propToUpperChangesLetter <span class="ot">=</span> forAll (elements [<span class="ch">'a'</span><span class="op">..</span><span class="ch">'z'</span>]) propToUpperChanges</span></code></pre></div>
|
||
<div class="sourceCode" id="cb414"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb414-1"><a href="#cb414-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> verboseCheck propToUpperChangesLetter</span>
|
||
<span id="cb414-2"><a href="#cb414-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Passed</span><span class="op">:</span></span>
|
||
<span id="cb414-3"><a href="#cb414-3" aria-hidden="true" tabindex="-1"></a><span class="ch">'s'</span></span>
|
||
<span id="cb414-4"><a href="#cb414-4" aria-hidden="true" tabindex="-1"></a><span class="ch">'S'</span> <span class="op">/=</span> <span class="ch">'s'</span></span>
|
||
<span id="cb414-5"><a href="#cb414-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb414-6"><a href="#cb414-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Passed</span><span class="op">:</span></span>
|
||
<span id="cb414-7"><a href="#cb414-7" aria-hidden="true" tabindex="-1"></a><span class="ch">'z'</span></span>
|
||
<span id="cb414-8"><a href="#cb414-8" aria-hidden="true" tabindex="-1"></a><span class="ch">'Z'</span> <span class="op">/=</span> <span class="ch">'z'</span></span>
|
||
<span id="cb414-9"><a href="#cb414-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- lots of output omitted</span></span>
|
||
<span id="cb414-10"><a href="#cb414-10" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">100</span> tests<span class="op">.</span></span></code></pre></div>
|
||
<p>Perfect! Let’s look at the types to see what’s going on here.</p>
|
||
<div class="sourceCode" id="cb415"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb415-1"><a href="#cb415-1" aria-hidden="true" tabindex="-1"></a><span class="ot">elements ::</span> [a] <span class="ot">-></span> <span class="dt">Gen</span> a</span>
|
||
<span id="cb415-2"><a href="#cb415-2" aria-hidden="true" tabindex="-1"></a>elements [<span class="ch">'a'</span><span class="op">..</span><span class="ch">'z'</span>]<span class="ot"> ::</span> <span class="dt">Gen</span> <span class="dt">Char</span></span>
|
||
<span id="cb415-3"><a href="#cb415-3" aria-hidden="true" tabindex="-1"></a><span class="ot">forAll ::</span> (<span class="dt">Show</span> a, <span class="dt">Testable</span> prop) <span class="ot">=></span> <span class="dt">Gen</span> a <span class="ot">-></span> (a <span class="ot">-></span> prop) <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb415-4"><a href="#cb415-4" aria-hidden="true" tabindex="-1"></a>forAll (elements [<span class="ch">'a'</span><span class="op">..</span><span class="ch">'z'</span>])<span class="ot"> ::</span> <span class="dt">Testable</span> prop <span class="ot">=></span> (<span class="dt">Char</span> <span class="ot">-></span> prop) <span class="ot">-></span> <span class="dt">Property</span></span></code></pre></div>
|
||
<p>There are some new types here. A value of type <code>Gen a</code> is
|
||
a generator for values of type <code>a</code>. We’ll talk a bit more
|
||
about <code>Gen</code> in the next section, but in this section you’ll
|
||
see a couple of functions that return <code>Gen</code>s so that we can
|
||
use them with <code>forAll</code>. The <code>elements</code> function is
|
||
a generator that returns one of the elements of the given list at
|
||
random, as you might have guessed.</p>
|
||
<p>The <code>Testable</code> type class is the same that the
|
||
<code>quickCheck</code> function uses. It exists so that
|
||
<code>quickCheck</code> can test types like
|
||
<code>[Int] -> Bool -> Property</code> in addition to just plain
|
||
<code>Property</code> values.</p>
|
||
<div class="sourceCode" id="cb416"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb416-1"><a href="#cb416-1" aria-hidden="true" tabindex="-1"></a><span class="ot">quickCheck ::</span> <span class="dt">Testable</span> prop <span class="ot">=></span> prop <span class="ot">-></span> <span class="dt">IO</span> ()</span></code></pre></div>
|
||
<p>In addition, some simple types like <code>Bool</code> have a
|
||
<code>Testable</code> instance, so that you can write tests using normal
|
||
Haskell predicates instead of <code>===</code>:</p>
|
||
<div class="sourceCode" id="cb417"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb417-1"><a href="#cb417-1" aria-hidden="true" tabindex="-1"></a><span class="ot">listHasZero ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb417-2"><a href="#cb417-2" aria-hidden="true" tabindex="-1"></a>listHasZero xs <span class="ot">=</span> <span class="fu">elem</span> <span class="dv">0</span> xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb418"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb418-1"><a href="#cb418-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck (listHasZero [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">2</span>])</span>
|
||
<span id="cb418-2"><a href="#cb418-2" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">1</span> test<span class="op">.</span></span>
|
||
<span id="cb418-3"><a href="#cb418-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck listHasZero</span>
|
||
<span id="cb418-4"><a href="#cb418-4" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Falsified</span> (after <span class="dv">1</span> test)<span class="op">:</span></span>
|
||
<span id="cb418-5"><a href="#cb418-5" aria-hidden="true" tabindex="-1"></a>[]</span></code></pre></div>
|
||
<p>Getting back to <code>forAll</code>, we can use <code>forAll</code>
|
||
to write more complex tests. Here’s a test that checks that
|
||
<code>sort xs</code> has the same elements as <code>xs</code>. Note how
|
||
we use <code>NonEmptyList</code> to guarantee that the
|
||
<code>forAll</code> has some elements to pick from.</p>
|
||
<div class="sourceCode" id="cb419"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb419-1"><a href="#cb419-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propSort ::</span> <span class="dt">NonEmptyList</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb419-2"><a href="#cb419-2" aria-hidden="true" tabindex="-1"></a>propSort (<span class="dt">NonEmpty</span> xs) <span class="ot">=</span></span>
|
||
<span id="cb419-3"><a href="#cb419-3" aria-hidden="true" tabindex="-1"></a> forAll (elements xs) (\x <span class="ot">-></span> <span class="fu">elem</span> x (<span class="fu">sort</span> xs))</span></code></pre></div>
|
||
<h3 data-number="16.1.3" id="further-with-quickcheck"><span
|
||
class="header-section-number">16.1.3</span> Further with QuickCheck</h3>
|
||
<p>We’ve only just scratched the surface of QuickCheck. Here are some
|
||
pointers to some things you’ll find useful when you start writing larger
|
||
QuickCheck tests.</p>
|
||
<p>Sometimes the output from QuickCheck isn’t quite verbose enough. You
|
||
can add your own lines to the output by using the
|
||
<code>counterexample</code> combinator:</p>
|
||
<div class="sourceCode" id="cb420"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb420-1"><a href="#cb420-1" aria-hidden="true" tabindex="-1"></a><span class="ot">counterexample ::</span> <span class="dt">Testable</span> prop <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> prop <span class="ot">-></span> <span class="dt">Property</span></span></code></pre></div>
|
||
<p>As an example, let’s add logging of the input to <code>rev</code> to
|
||
<code>propRevTwo</code>:</p>
|
||
<div class="sourceCode" id="cb421"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb421-1"><a href="#cb421-1" aria-hidden="true" tabindex="-1"></a><span class="ot">propRevTwo' ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb421-2"><a href="#cb421-2" aria-hidden="true" tabindex="-1"></a>propRevTwo' xs ys <span class="ot">=</span></span>
|
||
<span id="cb421-3"><a href="#cb421-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> input <span class="ot">=</span> xs <span class="op">++</span> ys</span>
|
||
<span id="cb421-4"><a href="#cb421-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> counterexample (<span class="st">"Input: "</span> <span class="op">++</span> <span class="fu">show</span> input) <span class="op">$</span></span>
|
||
<span id="cb421-5"><a href="#cb421-5" aria-hidden="true" tabindex="-1"></a> rev input <span class="op">===</span> rev ys <span class="op">++</span> rev xs</span></code></pre></div>
|
||
<div class="sourceCode" id="cb422"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb422-1"><a href="#cb422-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propRevTwo'</span>
|
||
<span id="cb422-2"><a href="#cb422-2" aria-hidden="true" tabindex="-1"></a><span class="op">***</span> <span class="dt">Failed</span><span class="op">!</span> <span class="dt">Falsified</span> (after <span class="dv">4</span> tests <span class="fu">and</span> <span class="dv">5</span> shrinks)<span class="op">:</span></span>
|
||
<span id="cb422-3"><a href="#cb422-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>]</span>
|
||
<span id="cb422-4"><a href="#cb422-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb422-5"><a href="#cb422-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Input</span><span class="op">:</span> [<span class="dv">0</span>,<span class="dv">0</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb422-6"><a href="#cb422-6" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>] <span class="op">/=</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span></code></pre></div>
|
||
<p>As you might have guessed, <code>Gen</code> is a <code>Monad</code>.
|
||
You can write your own generators by combining the generators defined by
|
||
QuickCheck. You can check what your generators output using
|
||
<code>sample</code>.</p>
|
||
<div class="sourceCode" id="cb423"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb423-1"><a href="#cb423-1" aria-hidden="true" tabindex="-1"></a><span class="ot">someLetters ::</span> <span class="dt">Gen</span> <span class="dt">String</span></span>
|
||
<span id="cb423-2"><a href="#cb423-2" aria-hidden="true" tabindex="-1"></a>someLetters <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb423-3"><a href="#cb423-3" aria-hidden="true" tabindex="-1"></a> c <span class="ot"><-</span> elements <span class="st">"xyzw"</span></span>
|
||
<span id="cb423-4"><a href="#cb423-4" aria-hidden="true" tabindex="-1"></a> n <span class="ot"><-</span> choose (<span class="dv">1</span>,<span class="dv">10</span>)</span>
|
||
<span id="cb423-5"><a href="#cb423-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> (<span class="fu">replicate</span> n c)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb424"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb424-1"><a href="#cb424-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> sample someLetters</span>
|
||
<span id="cb424-2"><a href="#cb424-2" aria-hidden="true" tabindex="-1"></a><span class="st">"yyyyyyyy"</span></span>
|
||
<span id="cb424-3"><a href="#cb424-3" aria-hidden="true" tabindex="-1"></a><span class="st">"zzzzzzzzz"</span></span>
|
||
<span id="cb424-4"><a href="#cb424-4" aria-hidden="true" tabindex="-1"></a><span class="st">"xxxxxxxxx"</span></span>
|
||
<span id="cb424-5"><a href="#cb424-5" aria-hidden="true" tabindex="-1"></a><span class="st">"yyyyyyy"</span></span>
|
||
<span id="cb424-6"><a href="#cb424-6" aria-hidden="true" tabindex="-1"></a><span class="st">"yyy"</span></span>
|
||
<span id="cb424-7"><a href="#cb424-7" aria-hidden="true" tabindex="-1"></a><span class="st">"ww"</span></span>
|
||
<span id="cb424-8"><a href="#cb424-8" aria-hidden="true" tabindex="-1"></a><span class="st">"xxxxxx"</span></span>
|
||
<span id="cb424-9"><a href="#cb424-9" aria-hidden="true" tabindex="-1"></a><span class="st">"yyy"</span></span>
|
||
<span id="cb424-10"><a href="#cb424-10" aria-hidden="true" tabindex="-1"></a><span class="st">"yyyyyyy"</span></span>
|
||
<span id="cb424-11"><a href="#cb424-11" aria-hidden="true" tabindex="-1"></a><span class="st">"xxxxxxxxxx"</span></span>
|
||
<span id="cb424-12"><a href="#cb424-12" aria-hidden="true" tabindex="-1"></a><span class="st">"y"</span></span></code></pre></div>
|
||
<p>Closely related to generators is the <code>Arbitrary</code> type
|
||
class. <code>Arbitrary</code> is how QuickCheck generates all those
|
||
inputs automatically.</p>
|
||
<div class="sourceCode" id="cb425"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb425-1"><a href="#cb425-1" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Arbitrary</span> a <span class="kw">where</span></span>
|
||
<span id="cb425-2"><a href="#cb425-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> arbitrary ::</span> <span class="dt">Gen</span> a</span>
|
||
<span id="cb425-3"><a href="#cb425-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> shrink ::</span> a <span class="ot">-></span> [a]</span></code></pre></div>
|
||
<p>If you’re writing tests for custom types, you either need to use
|
||
<code>forAll</code>, or implement an <code>Arbitrary</code> instance.
|
||
Here’s what happens if you’re missing an instance:</p>
|
||
<div class="sourceCode" id="cb426"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb426-1"><a href="#cb426-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Switch</span> <span class="ot">=</span> <span class="dt">On</span> <span class="op">|</span> <span class="dt">Off</span></span>
|
||
<span id="cb426-2"><a href="#cb426-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>)</span>
|
||
<span id="cb426-3"><a href="#cb426-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb426-4"><a href="#cb426-4" aria-hidden="true" tabindex="-1"></a><span class="ot">toggle ::</span> <span class="dt">Switch</span> <span class="ot">-></span> <span class="dt">Switch</span></span>
|
||
<span id="cb426-5"><a href="#cb426-5" aria-hidden="true" tabindex="-1"></a>toggle <span class="dt">On</span> <span class="ot">=</span> <span class="dt">Off</span></span>
|
||
<span id="cb426-6"><a href="#cb426-6" aria-hidden="true" tabindex="-1"></a>toggle <span class="dt">Off</span> <span class="ot">=</span> <span class="dt">On</span></span>
|
||
<span id="cb426-7"><a href="#cb426-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb426-8"><a href="#cb426-8" aria-hidden="true" tabindex="-1"></a><span class="ot">propToggleTwice ::</span> <span class="dt">Switch</span> <span class="ot">-></span> <span class="dt">Property</span></span>
|
||
<span id="cb426-9"><a href="#cb426-9" aria-hidden="true" tabindex="-1"></a>propToggleTwice s <span class="ot">=</span> s <span class="op">===</span> toggle (toggle s)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb427"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb427-1"><a href="#cb427-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck propToggleTwice</span>
|
||
<span id="cb427-2"><a href="#cb427-2" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb427-3"><a href="#cb427-3" aria-hidden="true" tabindex="-1"></a> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Arbitrary</span> <span class="dt">Switch</span>)</span>
|
||
<span id="cb427-4"><a href="#cb427-4" aria-hidden="true" tabindex="-1"></a> arising from a use <span class="kw">of</span> ‘quickCheck’</span>
|
||
<span id="cb427-5"><a href="#cb427-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the expression<span class="op">:</span> quickCheck propToggleTwice</span></code></pre></div>
|
||
<p>Here are the two ways to fix it:</p>
|
||
<div class="sourceCode" id="cb428"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb428-1"><a href="#cb428-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.QuickCheck</span><span class="op">></span> quickCheck (forAll (elements [<span class="dt">On</span>,<span class="dt">Off</span>]) propToggleTwice)</span>
|
||
<span id="cb428-2"><a href="#cb428-2" aria-hidden="true" tabindex="-1"></a><span class="op">+++</span> <span class="dt">OK</span>, passed <span class="dv">100</span> tests<span class="op">.</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb429"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb429-1"><a href="#cb429-1" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Arbitrary</span> <span class="dt">Switch</span> <span class="kw">where</span></span>
|
||
<span id="cb429-2"><a href="#cb429-2" aria-hidden="true" tabindex="-1"></a> arbitrary <span class="ot">=</span> elements [<span class="dt">On</span>,<span class="dt">Off</span>]</span></code></pre></div>
|
||
<!-- TODO (==>)? -->
|
||
<h2 data-number="16.2" id="phantom-types"><span
|
||
class="header-section-number">16.2</span> Phantom Types</h2>
|
||
<p>Boo! There’s a ghost in the type system! Let’s have a look at what
|
||
<em>phantom types</em> can do for you.</p>
|
||
<p>Phantom types are types that don’t take any values. They are related
|
||
to newtypes (see lecture 10) in that both are a way to add additional
|
||
type checking without affecting the evaluation of the program at
|
||
all.</p>
|
||
<p>Let’s use phantom types to track which currency an amount of money is
|
||
in. We define the phantom types <code>EUR</code> and <code>USD</code>
|
||
(note how they don’t have any constructors!), and the parameterized type
|
||
<code>Money a</code> that doesn’t use the type parameter <code>a</code>
|
||
for anything. Then we can define two constants, one in euros and the
|
||
other in dollars. You can find all of the code from this section in the
|
||
file <a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Examples/Phantom.hs"><code>exercises/Examples/Phantom.hs</code></a>.</p>
|
||
<div class="sourceCode" id="cb430"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb430-1"><a href="#cb430-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">EUR</span></span>
|
||
<span id="cb430-2"><a href="#cb430-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">USD</span></span>
|
||
<span id="cb430-3"><a href="#cb430-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Money</span> currency <span class="ot">=</span> <span class="dt">Money</span> <span class="dt">Double</span></span>
|
||
<span id="cb430-4"><a href="#cb430-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb430-5"><a href="#cb430-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb430-6"><a href="#cb430-6" aria-hidden="true" tabindex="-1"></a><span class="ot">dollar ::</span> <span class="dt">Money</span> <span class="dt">USD</span></span>
|
||
<span id="cb430-7"><a href="#cb430-7" aria-hidden="true" tabindex="-1"></a>dollar <span class="ot">=</span> <span class="dt">Money</span> <span class="dv">1</span></span>
|
||
<span id="cb430-8"><a href="#cb430-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb430-9"><a href="#cb430-9" aria-hidden="true" tabindex="-1"></a><span class="ot">twoEuros ::</span> <span class="dt">Money</span> <span class="dt">EUR</span></span>
|
||
<span id="cb430-10"><a href="#cb430-10" aria-hidden="true" tabindex="-1"></a>twoEuros <span class="ot">=</span> <span class="dt">Money</span> <span class="dv">2</span></span></code></pre></div>
|
||
<p>Note how the type signatures for <code>dollar</code> and
|
||
<code>twoEuros</code> are doing all the work here. An expression like
|
||
<code>Money 1</code> has the polymorphic type
|
||
<code>Money currency</code> if we don’t restrict it to a more specific
|
||
type. We give <code>dollar</code> and <code>twoEuros</code> more limited
|
||
types explicitly. This is analogous to defining something like
|
||
<code>one :: Int; one = 1</code>, since the constant <code>1</code> has
|
||
the polymorphic type <code>Num p => p</code> but we give it a more
|
||
restricted type.</p>
|
||
<div class="sourceCode" id="cb431"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb431-1"><a href="#cb431-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Money</span></span>
|
||
<span id="cb431-2"><a href="#cb431-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span><span class="ot"> ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Money</span> currency</span>
|
||
<span id="cb431-3"><a href="#cb431-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Money</span> <span class="dv">1</span></span>
|
||
<span id="cb431-4"><a href="#cb431-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span> <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Money</span> currency</span></code></pre></div>
|
||
<p>Now that we have some constants, we can write functions that operate
|
||
on them. Let’s start with a function <code>scaleMoney</code> that
|
||
multiplies an amount of money by a number. The currency stays constant.
|
||
Here too, the type signature is doing the work: without the type
|
||
signature, Haskell would infer a type of
|
||
<code>Double -> Money a -> Money b</code>.</p>
|
||
<div class="sourceCode" id="cb432"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb432-1"><a href="#cb432-1" aria-hidden="true" tabindex="-1"></a><span class="ot">scaleMoney ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Money</span> currency <span class="ot">-></span> <span class="dt">Money</span> currency</span>
|
||
<span id="cb432-2"><a href="#cb432-2" aria-hidden="true" tabindex="-1"></a>scaleMoney factor (<span class="dt">Money</span> a) <span class="ot">=</span> <span class="dt">Money</span> (factor <span class="op">*</span> a)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb433"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb433-1"><a href="#cb433-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t scaleMoney <span class="dv">3</span> twoEuros</span>
|
||
<span id="cb433-2"><a href="#cb433-2" aria-hidden="true" tabindex="-1"></a>scaleMoney <span class="dv">3</span><span class="ot"> twoEuros ::</span> <span class="dt">Money</span> <span class="dt">EUR</span></span>
|
||
<span id="cb433-3"><a href="#cb433-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t scaleMoney <span class="dv">3</span> dollar</span>
|
||
<span id="cb433-4"><a href="#cb433-4" aria-hidden="true" tabindex="-1"></a>scaleMoney <span class="dv">3</span><span class="ot"> dollar ::</span> <span class="dt">Money</span> <span class="dt">USD</span></span></code></pre></div>
|
||
<p>Next up: adding two amounts that are in the same currency. We get a
|
||
nice type error if we try to add values in two different currencies.</p>
|
||
<div class="sourceCode" id="cb434"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb434-1"><a href="#cb434-1" aria-hidden="true" tabindex="-1"></a><span class="ot">addMoney ::</span> <span class="dt">Money</span> currency <span class="ot">-></span> <span class="dt">Money</span> currency <span class="ot">-></span> <span class="dt">Money</span> currency</span>
|
||
<span id="cb434-2"><a href="#cb434-2" aria-hidden="true" tabindex="-1"></a>addMoney (<span class="dt">Money</span> a) (<span class="dt">Money</span> b) <span class="ot">=</span> <span class="dt">Money</span> (a<span class="op">+</span>b)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb435"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb435-1"><a href="#cb435-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t addMoney dollar dollar</span>
|
||
<span id="cb435-2"><a href="#cb435-2" aria-hidden="true" tabindex="-1"></a>addMoney dollar<span class="ot"> dollar ::</span> <span class="dt">Money</span> <span class="dt">USD</span></span>
|
||
<span id="cb435-3"><a href="#cb435-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t addMoney twoEuros twoEuros</span>
|
||
<span id="cb435-4"><a href="#cb435-4" aria-hidden="true" tabindex="-1"></a>addMoney twoEuros<span class="ot"> twoEuros ::</span> <span class="dt">Money</span> <span class="dt">EUR</span></span>
|
||
<span id="cb435-5"><a href="#cb435-5" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> <span class="op">:</span>t addMoney twoEuros dollar</span>
|
||
<span id="cb435-6"><a href="#cb435-6" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb435-7"><a href="#cb435-7" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match <span class="kw">type</span> ‘<span class="dt">USD</span>’ with ‘<span class="dt">EUR</span>’</span>
|
||
<span id="cb435-8"><a href="#cb435-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Money</span> <span class="dt">EUR</span></span>
|
||
<span id="cb435-9"><a href="#cb435-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Money</span> <span class="dt">USD</span></span>
|
||
<span id="cb435-10"><a href="#cb435-10" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘addMoney’, namely ‘dollar’</span>
|
||
<span id="cb435-11"><a href="#cb435-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> addMoney twoEuros dollar</span></code></pre></div>
|
||
<p>As before, the type signature is crucial. Here’s the same
|
||
implementation with an unrestricted type. Now we can add anything to
|
||
anything!</p>
|
||
<div class="sourceCode" id="cb436"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb436-1"><a href="#cb436-1" aria-hidden="true" tabindex="-1"></a><span class="ot">addMoneyUnsafe ::</span> <span class="dt">Money</span> x <span class="ot">-></span> <span class="dt">Money</span> y <span class="ot">-></span> <span class="dt">Money</span> z</span>
|
||
<span id="cb436-2"><a href="#cb436-2" aria-hidden="true" tabindex="-1"></a>addMoneyUnsafe (<span class="dt">Money</span> a) (<span class="dt">Money</span> b) <span class="ot">=</span> <span class="dt">Money</span> (a<span class="op">+</span>b)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb437"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb437-1"><a href="#cb437-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> addMoneyUnsafe twoEuros dollar</span>
|
||
<span id="cb437-2"><a href="#cb437-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span> <span class="fl">3.0</span></span></code></pre></div>
|
||
<p>We can keep going with this approach, and define currency
|
||
conversions. We define the type <code>Rate</code> that uses phantom
|
||
types to track the currencies it’s translating between. The types of
|
||
<code>convert</code> and <code>invert</code> are restricted to have the
|
||
properties we want. There’s also an unrestricted version of the convert
|
||
function to let you compare the types.</p>
|
||
<div class="sourceCode" id="cb438"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb438-1"><a href="#cb438-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Rate</span> from to <span class="ot">=</span> <span class="dt">Rate</span> <span class="dt">Double</span></span>
|
||
<span id="cb438-2"><a href="#cb438-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb438-3"><a href="#cb438-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb438-4"><a href="#cb438-4" aria-hidden="true" tabindex="-1"></a><span class="ot">eurToUsd ::</span> <span class="dt">Rate</span> <span class="dt">EUR</span> <span class="dt">USD</span></span>
|
||
<span id="cb438-5"><a href="#cb438-5" aria-hidden="true" tabindex="-1"></a>eurToUsd <span class="ot">=</span> <span class="dt">Rate</span> <span class="fl">1.22</span></span>
|
||
<span id="cb438-6"><a href="#cb438-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb438-7"><a href="#cb438-7" aria-hidden="true" tabindex="-1"></a><span class="ot">convert ::</span> <span class="dt">Rate</span> from to <span class="ot">-></span> <span class="dt">Money</span> from <span class="ot">-></span> <span class="dt">Money</span> to</span>
|
||
<span id="cb438-8"><a href="#cb438-8" aria-hidden="true" tabindex="-1"></a>convert (<span class="dt">Rate</span> r) (<span class="dt">Money</span> a) <span class="ot">=</span> <span class="dt">Money</span> (r<span class="op">*</span>a)</span>
|
||
<span id="cb438-9"><a href="#cb438-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb438-10"><a href="#cb438-10" aria-hidden="true" tabindex="-1"></a><span class="ot">invert ::</span> <span class="dt">Rate</span> from to <span class="ot">-></span> <span class="dt">Rate</span> to from</span>
|
||
<span id="cb438-11"><a href="#cb438-11" aria-hidden="true" tabindex="-1"></a>invert (<span class="dt">Rate</span> r) <span class="ot">=</span> <span class="dt">Rate</span> (<span class="dv">1</span><span class="op">/</span>r)</span>
|
||
<span id="cb438-12"><a href="#cb438-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb438-13"><a href="#cb438-13" aria-hidden="true" tabindex="-1"></a><span class="ot">convertUnsafe ::</span> <span class="dt">Rate</span> from to <span class="ot">-></span> <span class="dt">Money</span> x <span class="ot">-></span> <span class="dt">Money</span> y</span>
|
||
<span id="cb438-14"><a href="#cb438-14" aria-hidden="true" tabindex="-1"></a>convertUnsafe (<span class="dt">Rate</span> r) (<span class="dt">Money</span> a) <span class="ot">=</span> <span class="dt">Money</span> (r<span class="op">*</span>a)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb439"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb439-1"><a href="#cb439-1" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> convert eurToUsd twoEuros</span>
|
||
<span id="cb439-2"><a href="#cb439-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span> <span class="fl">2.44</span></span>
|
||
<span id="cb439-3"><a href="#cb439-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> convert eurToUsd dollar</span>
|
||
<span id="cb439-4"><a href="#cb439-4" aria-hidden="true" tabindex="-1"></a><span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb439-5"><a href="#cb439-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match <span class="kw">type</span> ‘<span class="dt">USD</span>’ with ‘<span class="dt">EUR</span>’</span>
|
||
<span id="cb439-6"><a href="#cb439-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Money</span> <span class="dt">EUR</span></span>
|
||
<span id="cb439-7"><a href="#cb439-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">Money</span> <span class="dt">USD</span></span>
|
||
<span id="cb439-8"><a href="#cb439-8" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘convert’, namely ‘dollar’</span>
|
||
<span id="cb439-9"><a href="#cb439-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> convert eurToUsd dollar</span>
|
||
<span id="cb439-10"><a href="#cb439-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> convert eurToUsd dollar</span>
|
||
<span id="cb439-11"><a href="#cb439-11" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> convert (invert eurToUsd) dollar</span>
|
||
<span id="cb439-12"><a href="#cb439-12" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span> <span class="fl">0.819672131147541</span></span>
|
||
<span id="cb439-13"><a href="#cb439-13" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Examples.Phantom</span><span class="op">></span> convertUnsafe eurToUsd dollar</span>
|
||
<span id="cb439-14"><a href="#cb439-14" aria-hidden="true" tabindex="-1"></a><span class="dt">Money</span> <span class="fl">1.22</span></span></code></pre></div>
|
||
<p>Note! The words <code>currency</code>, <code>from</code>,
|
||
<code>to</code> and so forth in the previous examples are <em>just type
|
||
variables</em>. There’s nothing special going on with them. We could’ve
|
||
as well given <code>invert</code> a type like
|
||
<code>Rate a b -> Rate b a</code> without any change in type
|
||
safety.</p>
|
||
<p>This approach that uses phantom types has clear benefits: giving us
|
||
type errors for invalid code. Also, compared to defining lots of
|
||
concrete types like <code>data MoneyEur = MoneyEur Double</code>, with
|
||
phantom types we need to implement functions like
|
||
<code>scaleMoney</code> and <code>addMoney</code> only once. Also, we’re
|
||
able to define polymorphic and reusable concepts like <code>Rate</code>.
|
||
You can contrast this approach with the Boxing section of Lecture 7.</p>
|
||
<p>However, phantom types also have downsides. Without advanced tricks
|
||
we can’t really handle currencies that are defined at runtime (for
|
||
example: reading an amount from a user). It’s also easy to end up in a
|
||
place where you start needing language extensions like <a
|
||
href="https://wiki.haskell.org/GADTs_for_dummies"><em>Generalized
|
||
Algebraic Datatypes</em></a>, <a
|
||
href="https://wiki.haskell.org/GHC/Type_families"><em>type
|
||
families</em></a> and other <a
|
||
href="https://aphyr.com/posts/342-typing-the-technical-interview"><em>type-level
|
||
programming</em></a> constructs. Eventually you’re all the way in the
|
||
world of <a
|
||
href="https://mitpress.mit.edu/books/little-typer"><em>dependent
|
||
typing</em></a>.</p>
|
||
<p>So what are good applications for phantom types? When you need to
|
||
track some simple, but crucial information, that is known at
|
||
compile-time. An example that’s somewhat better than currencies is
|
||
tracking whether inputs from the user have been sanitated to prevent
|
||
attacks like <a href="https://en.wikipedia.org/wiki/SQL_injection">SQL
|
||
injection</a> or <a
|
||
href="https://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
|
||
scripting</a>.</p>
|
||
<p>We can use the types <code>Input Safe</code> and
|
||
<code>Input Unsafe</code> to track whether strings are safe for passing
|
||
into the database or not. If our module only exports the
|
||
<code>makeInput</code> function, and not the <code>Input</code>
|
||
constructor, the type system ensures that any inputs must pass through
|
||
the <code>escapeInput</code> function at some point before going into a
|
||
database function like <code>addForumComment</code>.</p>
|
||
<div class="sourceCode" id="cb440"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb440-1"><a href="#cb440-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Safe</span></span>
|
||
<span id="cb440-2"><a href="#cb440-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Unsafe</span></span>
|
||
<span id="cb440-3"><a href="#cb440-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-4"><a href="#cb440-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Input</span> a <span class="ot">=</span> <span class="dt">Input</span> <span class="dt">String</span></span>
|
||
<span id="cb440-5"><a href="#cb440-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-6"><a href="#cb440-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- Public constructor function for Input, only allows constructing</span></span>
|
||
<span id="cb440-7"><a href="#cb440-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- Unsafe Inputs from Strings.</span></span>
|
||
<span id="cb440-8"><a href="#cb440-8" aria-hidden="true" tabindex="-1"></a><span class="ot">makeInput ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Input</span> <span class="dt">Unsafe</span></span>
|
||
<span id="cb440-9"><a href="#cb440-9" aria-hidden="true" tabindex="-1"></a>makeInput xs <span class="ot">=</span> <span class="dt">Input</span> xs</span>
|
||
<span id="cb440-10"><a href="#cb440-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-11"><a href="#cb440-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- Adds comment to the database.</span></span>
|
||
<span id="cb440-12"><a href="#cb440-12" aria-hidden="true" tabindex="-1"></a><span class="ot">addForumComment ::</span> <span class="dt">Input</span> <span class="dt">Safe</span> <span class="ot">-></span> <span class="dt">IO</span> <span class="dt">Result</span></span>
|
||
<span id="cb440-13"><a href="#cb440-13" aria-hidden="true" tabindex="-1"></a>addForumComment <span class="ot">=</span> <span class="op">...</span></span>
|
||
<span id="cb440-14"><a href="#cb440-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-15"><a href="#cb440-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- We can combine inputs, but that won't change their safety</span></span>
|
||
<span id="cb440-16"><a href="#cb440-16" aria-hidden="true" tabindex="-1"></a><span class="ot">concatInputs ::</span> <span class="dt">Input</span> a <span class="ot">-></span> <span class="dt">Input</span> a <span class="ot">-></span> <span class="dt">Input</span> a</span>
|
||
<span id="cb440-17"><a href="#cb440-17" aria-hidden="true" tabindex="-1"></a>concatInputs (<span class="dt">Input</span> xs) (<span class="dt">Input</span> ys) <span class="ot">=</span> <span class="dt">Input</span> (xs<span class="op">++</span>ys)</span>
|
||
<span id="cb440-18"><a href="#cb440-18" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-19"><a href="#cb440-19" aria-hidden="true" tabindex="-1"></a><span class="co">-- Strip bad characters to turn an unsafe input safe</span></span>
|
||
<span id="cb440-20"><a href="#cb440-20" aria-hidden="true" tabindex="-1"></a><span class="ot">escapeInput ::</span> <span class="dt">Input</span> <span class="dt">Unsafe</span> <span class="ot">-></span> <span class="dt">Input</span> <span class="dt">Safe</span></span>
|
||
<span id="cb440-21"><a href="#cb440-21" aria-hidden="true" tabindex="-1"></a>escapeInput (<span class="dt">Input</span> xs) <span class="ot">=</span> <span class="dt">Input</span> (<span class="fu">filter</span> (\c <span class="ot">-></span> <span class="fu">isAlpha</span> c <span class="op">||</span> <span class="fu">isSpace</span> c) xs)</span></code></pre></div>
|
||
<h2 data-number="16.3" id="simultaneity"><span
|
||
class="header-section-number">16.3</span> Simultaneity</h2>
|
||
<h3 data-number="16.3.1" id="parallelism"><span
|
||
class="header-section-number">16.3.1</span> Parallelism</h3>
|
||
<p>One of the great things about purity is that it makes
|
||
<em>parallelism</em>, computing many things at the same time, very easy.
|
||
Let’s have a look at how we can do this in Haskell. First off, we need
|
||
to start a new GHCi that has parallel execution enabled. The simplest
|
||
way is:</p>
|
||
<pre><code>$ stack ghci --ghci-options "+RTS -N"</code></pre>
|
||
<p>Next up, let’s define a very naive version of the Fibonacci function
|
||
(remember Lecture 1?) , enable performance statistics with
|
||
<code>:set +s</code>, and see how long it takes to compute five values
|
||
of the function:</p>
|
||
<div class="sourceCode" id="cb442"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb442-1"><a href="#cb442-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> fib <span class="dv">0</span> <span class="ot">=</span> <span class="dv">1</span>; fib <span class="dv">1</span> <span class="ot">=</span> <span class="dv">1</span>; fib n <span class="ot">=</span> fib (n<span class="op">-</span><span class="dv">1</span>) <span class="op">+</span> fib (n<span class="op">-</span><span class="dv">2</span>)</span>
|
||
<span id="cb442-2"><a href="#cb442-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>set <span class="op">+</span>s</span>
|
||
<span id="cb442-3"><a href="#cb442-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</span> fib [<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>]</span>
|
||
<span id="cb442-4"><a href="#cb442-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>]</span>
|
||
<span id="cb442-5"><a href="#cb442-5" aria-hidden="true" tabindex="-1"></a>(<span class="fl">7.54</span> secs, <span class="dv">2</span>,<span class="dv">440</span>,<span class="dv">860</span>,<span class="dv">632</span> bytes)</span></code></pre></div>
|
||
<p>Now let’s bring in the module <a
|
||
href="https://hackage.haskell.org/package/parallel-3.2.2.0/docs/Control-Parallel-Strategies.html">Control.Parallel.Strategies</a>
|
||
that defines ways to evaluate values in parallel. We’ll use the
|
||
<code>parList rseq</code> strategy to evaluate all the elements of the
|
||
list to WHNF, <em>in parallel</em>.</p>
|
||
<div class="sourceCode" id="cb443"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb443-1"><a href="#cb443-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Control.Parallel.Strategies</span></span>
|
||
<span id="cb443-2"><a href="#cb443-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Control.Parallel.Strategies</span><span class="op">></span> withStrategy (parList rseq) (<span class="fu">map</span> fib [<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>,<span class="dv">29</span>])</span>
|
||
<span id="cb443-3"><a href="#cb443-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>,<span class="dv">832040</span>]</span>
|
||
<span id="cb443-4"><a href="#cb443-4" aria-hidden="true" tabindex="-1"></a>(<span class="fl">4.80</span> secs, <span class="dv">488</span>,<span class="dv">531</span>,<span class="dv">384</span> bytes)</span></code></pre></div>
|
||
<p>That’s almost 2 times as fast, on the 2-core machine that this
|
||
example is being run on. Pretty nice. The coolest thing here is that we
|
||
were able to define the <em>computation</em> (<code>map fib ...</code>)
|
||
completely separately from the <em>evaluation strategy</em>
|
||
(<code>parList rseq</code>), separating the <em>what to compute</em>
|
||
from the <em>how to compute</em>.</p>
|
||
<h3 data-number="16.3.2" id="concurrency"><span
|
||
class="header-section-number">16.3.2</span> Concurrency</h3>
|
||
<p>Computer science makes the distinction between parallel and
|
||
<em>concurrent</em> computations. Parallel computations are those that
|
||
just run separate independent computations in parallel (in other words,
|
||
parallelism is <em>pure</em>). Concurrent computations are those where
|
||
there are multiple interacting threads of computation. Concurrency
|
||
usually involves threads, locks, messages and deadlocks.</p>
|
||
<p>In addition to great tooling for parallelism, Haskell also has good
|
||
tooling for concurrency via <em>threads</em>. Since concurrency is all
|
||
about side-effects, concurrent computations happen in the
|
||
<code>IO</code> Monad. The classic example of threading is two threads,
|
||
one printing a stream of As and the other a stream of Bs. Here it is in
|
||
Haskell:</p>
|
||
<div class="sourceCode" id="cb444"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb444-1"><a href="#cb444-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printA ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb444-2"><a href="#cb444-2" aria-hidden="true" tabindex="-1"></a>printA <span class="ot">=</span> <span class="fu">putStrLn</span> (<span class="fu">replicate</span> <span class="dv">40</span> <span class="ch">'A'</span>)</span>
|
||
<span id="cb444-3"><a href="#cb444-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb444-4"><a href="#cb444-4" aria-hidden="true" tabindex="-1"></a><span class="ot">printB ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb444-5"><a href="#cb444-5" aria-hidden="true" tabindex="-1"></a>printB <span class="ot">=</span> <span class="fu">putStrLn</span> (<span class="fu">replicate</span> <span class="dv">40</span> <span class="ch">'B'</span>)</span>
|
||
<span id="cb444-6"><a href="#cb444-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb444-7"><a href="#cb444-7" aria-hidden="true" tabindex="-1"></a><span class="ot">concurrency ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb444-8"><a href="#cb444-8" aria-hidden="true" tabindex="-1"></a>concurrency <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb444-9"><a href="#cb444-9" aria-hidden="true" tabindex="-1"></a> forkIO printA</span>
|
||
<span id="cb444-10"><a href="#cb444-10" aria-hidden="true" tabindex="-1"></a> forkIO printB</span>
|
||
<span id="cb444-11"><a href="#cb444-11" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> ()</span></code></pre></div>
|
||
<pre><code>Prelude Control.Concurrent> concurrency
|
||
AABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABABB</code></pre>
|
||
<p>The operation <code>forkIO :: IO () -> IO ThreadId</code> takes an
|
||
IO operation and starts running it in the background. It produces a
|
||
<code>ThreadId</code> that can be used to e.g. terminate the thread.</p>
|
||
<p>If we want to add actual communication between threads, we can use
|
||
abstractions like <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Control-Concurrent-MVar.html"><code>MVar</code></a>
|
||
(a mutable thread-safe variable) or <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Control-Concurrent-Chan.html"><code>Chan</code></a>
|
||
(a queue).</p>
|
||
<p>Here’s a simple example where one thread writes a value to an
|
||
<code>MVar</code> and another one waits for them and prints them. An
|
||
<code>MVar</code> works like a mailbox: it is either empty or full.
|
||
Calling <code>takeMVar</code> on an empty box waits for the box to get
|
||
filled (with a <code>putMVar</code>). Symmetrically, trying to
|
||
<code>putMVar</code> into a full box waits until the box is empty.</p>
|
||
<div class="sourceCode" id="cb446"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb446-1"><a href="#cb446-1" aria-hidden="true" tabindex="-1"></a><span class="ot">takeMVar ::</span> <span class="dt">MVar</span> a <span class="ot">-></span> <span class="dt">IO</span> a</span>
|
||
<span id="cb446-2"><a href="#cb446-2" aria-hidden="true" tabindex="-1"></a><span class="ot">putMVar ::</span> <span class="dt">MVar</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb446-3"><a href="#cb446-3" aria-hidden="true" tabindex="-1"></a><span class="ot">newEmptyMVar ::</span> <span class="dt">IO</span> (<span class="dt">MVar</span> a)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb447"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb447-1"><a href="#cb447-1" aria-hidden="true" tabindex="-1"></a><span class="ot">send ::</span> [<span class="dt">String</span>] <span class="ot">-></span> <span class="dt">MVar</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb447-2"><a href="#cb447-2" aria-hidden="true" tabindex="-1"></a>send values var <span class="ot">=</span> <span class="fu">mapM_</span> (putMVar var) values</span>
|
||
<span id="cb447-3"><a href="#cb447-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb447-4"><a href="#cb447-4" aria-hidden="true" tabindex="-1"></a><span class="ot">receive ::</span> <span class="dt">MVar</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb447-5"><a href="#cb447-5" aria-hidden="true" tabindex="-1"></a>receive var <span class="ot">=</span> <span class="kw">do</span> val <span class="ot"><-</span> takeMVar var</span>
|
||
<span id="cb447-6"><a href="#cb447-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> val</span>
|
||
<span id="cb447-7"><a href="#cb447-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- loop unless at last value</span></span>
|
||
<span id="cb447-8"><a href="#cb447-8" aria-hidden="true" tabindex="-1"></a> when (val<span class="op">/=</span><span class="st">"end"</span>) (receive var)</span>
|
||
<span id="cb447-9"><a href="#cb447-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb447-10"><a href="#cb447-10" aria-hidden="true" tabindex="-1"></a><span class="ot">concurrency2 ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb447-11"><a href="#cb447-11" aria-hidden="true" tabindex="-1"></a>concurrency2 <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb447-12"><a href="#cb447-12" aria-hidden="true" tabindex="-1"></a> var <span class="ot"><-</span> newEmptyMVar</span>
|
||
<span id="cb447-13"><a href="#cb447-13" aria-hidden="true" tabindex="-1"></a> forkIO (send [<span class="st">"hello"</span>,<span class="st">"world"</span>,<span class="st">"and"</span>,<span class="st">"goodbye"</span>,<span class="st">"end"</span>] var)</span>
|
||
<span id="cb447-14"><a href="#cb447-14" aria-hidden="true" tabindex="-1"></a> forkIO (receive var)</span>
|
||
<span id="cb447-15"><a href="#cb447-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">return</span> ()</span></code></pre></div>
|
||
<div class="sourceCode" id="cb448"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb448-1"><a href="#cb448-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Control.Concurrent</span> <span class="dt">Control.Monad</span><span class="op">></span> concurrency2</span>
|
||
<span id="cb448-2"><a href="#cb448-2" aria-hidden="true" tabindex="-1"></a><span class="st">"hello"</span></span>
|
||
<span id="cb448-3"><a href="#cb448-3" aria-hidden="true" tabindex="-1"></a><span class="st">"world"</span></span>
|
||
<span id="cb448-4"><a href="#cb448-4" aria-hidden="true" tabindex="-1"></a><span class="st">"and"</span></span>
|
||
<span id="cb448-5"><a href="#cb448-5" aria-hidden="true" tabindex="-1"></a><span class="st">"goodbye"</span></span>
|
||
<span id="cb448-6"><a href="#cb448-6" aria-hidden="true" tabindex="-1"></a><span class="st">"end"</span></span></code></pre></div>
|
||
<h2 data-number="16.4" id="exercises-7"><span
|
||
class="header-section-number">16.4</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set16a.hs">Set16a</a>:
|
||
QuickCheck</li>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set16b.hs">Set16b</a>:
|
||
Phantom types</li>
|
||
<li>No exercises for parallel or concurrent Haskell, sorry!</li>
|
||
</ul>
|
||
<h2 data-number="16.5" id="where-to-go-from-here"><span
|
||
class="header-section-number">16.5</span> Where to Go From Here?</h2>
|
||
<p>Congratulations! You’ve reached the end of this two part course on
|
||
Functional Programming in Haskell. What next? You definitely know enough
|
||
Haskell to keep learning on your own. The online Haskell community is
|
||
very friendly and there are lots of blog posts and other content
|
||
explaining advanced techniques and features. You can find lots of
|
||
interesting stuff by following for example:</p>
|
||
<ul>
|
||
<li><a href="https://www.reddit.com/r/haskell/">/r/haskell</a> on
|
||
reddit</li>
|
||
<li><code>#haskell</code> on <a
|
||
href="https://libera.chat">libera.chat</a></li>
|
||
<li><a href="https://haskellweekly.news/">Haskell Weekly</a></li>
|
||
<li>StackOverflow</li>
|
||
</ul>
|
||
<p>Just keep writing Haskell, studying things (like libraries and tools)
|
||
when you bump into them, and slowly accumulate experience. Lots of the
|
||
things you learn with Haskell will be transferable to other languages
|
||
like <a href="https://www.typescriptlang.org/">TypeScript</a>, <a
|
||
href="https://elm-lang.org/">Elm</a>, <a
|
||
href="https://www.rust-lang.org/">Rust</a> or <a
|
||
href="https://fsharp.org/">F#</a>.</p>
|
||
<p>Finally, here is an incomplete list of things that got left out of
|
||
this course, but are worth looking into:</p>
|
||
<ul>
|
||
<li>Language features
|
||
<ul>
|
||
<li><a
|
||
href="https://en.wikibooks.org/wiki/Haskell/Modules">Modules</a></li>
|
||
<li>Lazy patterns (<code>~</code> patterns) and <code>@</code> patterns.
|
||
See e.g. <a href="https://www.haskell.org/tutorial/patterns.html">A
|
||
Gentle Introduction to Haskell</a>.</li>
|
||
<li>Language extensions like <code>MultiParamTypeClasses</code>,
|
||
<code>ViewPatterns</code> etc. <a
|
||
href="https://limperg.de/ghc-extensions/">This is one good
|
||
guide</a></li>
|
||
<li>The <code>fix</code> function</li>
|
||
<li>The Foreign Function Interface for calling C code from Haskell</li>
|
||
</ul></li>
|
||
<li>Abstractions
|
||
<ul>
|
||
<li>Monad transformers: <a
|
||
href="https://book.realworldhaskell.org/read/monad-transformers.html">RWH</a>,
|
||
<a
|
||
href="https://en.wikibooks.org/wiki/Haskell/Monad_transformers">Wikibook</a></li>
|
||
<li>Free monads (advanced topic): <a
|
||
href="https://www.haskellforall.com/2012/06/you-could-have-invented-free-monads.html">blog</a></li>
|
||
<li>Lenses (advanced topic): <a
|
||
href="https://hackage.haskell.org/package/lens-tutorial-1.0.4/docs/Control-Lens-Tutorial.html">tutorial</a>
|
||
<a
|
||
href="https://oleg.fi/gists/posts/2017-04-18-glassery.html">glassery</a></li>
|
||
<li><a href="https://bartoszmilewski.com/">Bartosz Milewski</a> covers
|
||
lots of intermediate and advanced topics on his blog</li>
|
||
</ul></li>
|
||
<li>Tooling
|
||
<ul>
|
||
<li>Using <a href="https://www.haskell.org/cabal/">Cabal</a> and <a
|
||
href="https://www.haskellstack.org">Stack</a> to build your own
|
||
projects</li>
|
||
<li>Profiling: <a
|
||
href="https://book.realworldhaskell.org/read/profiling-and-optimization.html">RWH</a>,
|
||
<a
|
||
href="https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/profiling.html">GHC</a></li>
|
||
<li><a href="https://github.com/ndmitchell/hlint#readme">Hlint</a></li>
|
||
</ul></li>
|
||
<li>Libraries
|
||
<ul>
|
||
<li>Parsec (parsing): <a
|
||
href="https://book.realworldhaskell.org/read/using-parsec.html">RWH</a></li>
|
||
<li>Scotty (simple web framework), Aeson (json): <a
|
||
href="https://seanhess.github.io/2015/08/19/practical-haskell-json-api.html">blog</a></li>
|
||
<li><a href="https://haskell-servant.github.io/">Servant</a> (fancy web
|
||
framework with phantom types)</li>
|
||
</ul></li>
|
||
<li>Category theory
|
||
<ul>
|
||
<li>Many Haskell abstractions are based on Category theory</li>
|
||
<li>Category theory can be a valuable source of new ideas for
|
||
programming</li>
|
||
<li>Category theory can feel intimidating, so it’s good to know that you
|
||
can get on fine without it</li>
|
||
<li>Bartosz Milewski has lots of good material, for example <a
|
||
href="https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/">Category
|
||
Theory for Programmers</a></li>
|
||
<li>The <a href="https://wiki.haskell.org/Category_theory">Haskell
|
||
Wiki</a> and <a
|
||
href="https://en.wikibooks.org/wiki/Haskell/Category_theory">Wikibook</a>
|
||
have sections on category theory</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h2 data-number="16.6" id="acknowledgements"><span
|
||
class="header-section-number">16.6</span> Acknowledgements</h2>
|
||
<p>This course was made possible by <a
|
||
href="https://nitor.com/en">Nitor</a> who donated hours and hours of
|
||
Joel’s working time for this project. Thank you!</p>
|
||
<p>Thanks to the whole Haskell Mooc team, especially</p>
|
||
<ul>
|
||
<li>John Lång for help on the material</li>
|
||
<li>Antti Laaksonen for setting up the course and helping with
|
||
arrangements</li>
|
||
<li>Topi Talvitie for the exercise checking infrastructure</li>
|
||
</ul>
|
||
<p>Thanks to all the students who patiently waited for part 2 and
|
||
reported errors in the material & exercises!</p>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|