mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
6429 lines
633 KiB
HTML
6429 lines
633 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 1</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-1-and-so-it-begins"
|
||
id="toc-lecture-1-and-so-it-begins"><span
|
||
class="toc-section-number">1</span> Lecture 1: …And so It Begins</a>
|
||
<ul>
|
||
<li><a href="#about-the-course" id="toc-about-the-course"><span
|
||
class="toc-section-number">1.1</span> About the Course</a></li>
|
||
<li><a href="#read-these" id="toc-read-these"><span
|
||
class="toc-section-number">1.2</span> Read These</a></li>
|
||
<li><a href="#haskell" id="toc-haskell"><span
|
||
class="toc-section-number">1.3</span> Haskell</a></li>
|
||
<li><a href="#running-haskell" id="toc-running-haskell"><span
|
||
class="toc-section-number">1.4</span> Running Haskell</a></li>
|
||
<li><a href="#lets-start" id="toc-lets-start"><span
|
||
class="toc-section-number">1.5</span> Let’s Start!</a></li>
|
||
<li><a href="#expressions-and-types"
|
||
id="toc-expressions-and-types"><span
|
||
class="toc-section-number">1.6</span> Expressions and Types</a></li>
|
||
<li><a href="#the-structure-of-a-haskell-program"
|
||
id="toc-the-structure-of-a-haskell-program"><span
|
||
class="toc-section-number">1.7</span> The Structure of a Haskell
|
||
Program</a></li>
|
||
<li><a href="#working-with-examples"
|
||
id="toc-working-with-examples"><span
|
||
class="toc-section-number">1.8</span> Working with Examples</a></li>
|
||
<li><a href="#how-do-i-get-anything-done"
|
||
id="toc-how-do-i-get-anything-done"><span
|
||
class="toc-section-number">1.9</span> How Do I Get Anything
|
||
Done?</a></li>
|
||
<li><a href="#all-together-now" id="toc-all-together-now"><span
|
||
class="toc-section-number">1.10</span> All Together Now!</a></li>
|
||
<li><a href="#a-word-about-indentation"
|
||
id="toc-a-word-about-indentation"><span
|
||
class="toc-section-number">1.11</span> A Word About Indentation</a></li>
|
||
<li><a href="#quiz" id="toc-quiz"><span
|
||
class="toc-section-number">1.12</span> Quiz</a></li>
|
||
<li><a href="#working-on-the-exercises"
|
||
id="toc-working-on-the-exercises"><span
|
||
class="toc-section-number">1.13</span> Working on the Exercises</a></li>
|
||
<li><a href="#exercises" id="toc-exercises"><span
|
||
class="toc-section-number">1.14</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-2-either-you-die-a-hero"
|
||
id="toc-lecture-2-either-you-die-a-hero"><span
|
||
class="toc-section-number">2</span> Lecture 2: Either You Die a
|
||
Hero…</a>
|
||
<ul>
|
||
<li><a href="#recursion-and-helper-functions"
|
||
id="toc-recursion-and-helper-functions"><span
|
||
class="toc-section-number">2.1</span> Recursion and Helper
|
||
Functions</a></li>
|
||
<li><a href="#guards" id="toc-guards"><span
|
||
class="toc-section-number">2.2</span> Guards</a></li>
|
||
<li><a href="#lists" id="toc-lists"><span
|
||
class="toc-section-number">2.3</span> Lists</a></li>
|
||
<li><a href="#a-word-about-immutability-1"
|
||
id="toc-a-word-about-immutability-1"><span
|
||
class="toc-section-number">2.4</span> A Word About Immutability</a></li>
|
||
<li><a href="#a-word-about-type-inference-and-polymorphism"
|
||
id="toc-a-word-about-type-inference-and-polymorphism"><span
|
||
class="toc-section-number">2.5</span> A Word About Type Inference and
|
||
Polymorphism</a></li>
|
||
<li><a href="#the-maybe-type" id="toc-the-maybe-type"><span
|
||
class="toc-section-number">2.6</span> The <code>Maybe</code>
|
||
Type</a></li>
|
||
<li><a href="#sidenote-constructors"
|
||
id="toc-sidenote-constructors"><span
|
||
class="toc-section-number">2.7</span> Sidenote: Constructors</a></li>
|
||
<li><a href="#the-either-type" id="toc-the-either-type"><span
|
||
class="toc-section-number">2.8</span> The <code>Either</code>
|
||
type</a></li>
|
||
<li><a href="#the-case-of-expression"
|
||
id="toc-the-case-of-expression"><span
|
||
class="toc-section-number">2.9</span> The case-of Expression</a></li>
|
||
<li><a href="#recap-pattern-matching"
|
||
id="toc-recap-pattern-matching"><span
|
||
class="toc-section-number">2.10</span> Recap: Pattern Matching</a></li>
|
||
<li><a href="#quiz-1" id="toc-quiz-1"><span
|
||
class="toc-section-number">2.11</span> Quiz</a></li>
|
||
<li><a href="#exercises-1" id="toc-exercises-1"><span
|
||
class="toc-section-number">2.12</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-3-catamorphic"
|
||
id="toc-lecture-3-catamorphic"><span class="toc-section-number">3</span>
|
||
Lecture 3: Catamorphic</a>
|
||
<ul>
|
||
<li><a href="#functional-programming-at-last"
|
||
id="toc-functional-programming-at-last"><span
|
||
class="toc-section-number">3.1</span> Functional Programming, at
|
||
Last</a></li>
|
||
<li><a href="#partial-application" id="toc-partial-application"><span
|
||
class="toc-section-number">3.2</span> Partial Application</a></li>
|
||
<li><a href="#prefix-and-infix-notations"
|
||
id="toc-prefix-and-infix-notations"><span
|
||
class="toc-section-number">3.3</span> Prefix and Infix
|
||
Notations</a></li>
|
||
<li><a href="#lambdas" id="toc-lambdas"><span
|
||
class="toc-section-number">3.4</span> Lambdas</a></li>
|
||
<li><a href="#sidenote-the-.-and-operators"
|
||
id="toc-sidenote-the-.-and-operators"><span
|
||
class="toc-section-number">3.5</span> Sidenote: The <code>.</code> and
|
||
<code>$</code> Operators</a></li>
|
||
<li><a href="#example-rewriting-whatfollows"
|
||
id="toc-example-rewriting-whatfollows"><span
|
||
class="toc-section-number">3.6</span> Example: Rewriting
|
||
<code>whatFollows</code></a></li>
|
||
<li><a href="#more-functional-list-wrangling-examples"
|
||
id="toc-more-functional-list-wrangling-examples"><span
|
||
class="toc-section-number">3.7</span> More Functional List Wrangling
|
||
Examples</a></li>
|
||
<li><a href="#lists-and-recursion" id="toc-lists-and-recursion"><span
|
||
class="toc-section-number">3.8</span> Lists and Recursion</a></li>
|
||
<li><a href="#something-fun-list-comprehensions"
|
||
id="toc-something-fun-list-comprehensions"><span
|
||
class="toc-section-number">3.9</span> Something Fun: List
|
||
Comprehensions</a></li>
|
||
<li><a href="#something-fun-custom-operators"
|
||
id="toc-something-fun-custom-operators"><span
|
||
class="toc-section-number">3.10</span> Something Fun: Custom
|
||
Operators</a></li>
|
||
<li><a href="#something-useful-typed-holes"
|
||
id="toc-something-useful-typed-holes"><span
|
||
class="toc-section-number">3.11</span> Something Useful: Typed
|
||
Holes</a></li>
|
||
<li><a href="#quiz-2" id="toc-quiz-2"><span
|
||
class="toc-section-number">3.12</span> Quiz</a></li>
|
||
<li><a href="#exercises-2" id="toc-exercises-2"><span
|
||
class="toc-section-number">3.13</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-4-real-classy"
|
||
id="toc-lecture-4-real-classy"><span class="toc-section-number">4</span>
|
||
Lecture 4: Real Classy</a>
|
||
<ul>
|
||
<li><a href="#sidenote-tuples" id="toc-sidenote-tuples"><span
|
||
class="toc-section-number">4.1</span> Sidenote: Tuples</a></li>
|
||
<li><a href="#interlude-folding" id="toc-interlude-folding"><span
|
||
class="toc-section-number">4.2</span> Interlude: Folding</a></li>
|
||
<li><a href="#type-classes" id="toc-type-classes"><span
|
||
class="toc-section-number">4.3</span> Type Classes</a></li>
|
||
<li><a href="#type-constraints" id="toc-type-constraints"><span
|
||
class="toc-section-number">4.4</span> Type Constraints</a></li>
|
||
<li><a href="#standard-type-classes"
|
||
id="toc-standard-type-classes"><span
|
||
class="toc-section-number">4.5</span> Standard Type Classes</a></li>
|
||
<li><a href="#more-data-structures" id="toc-more-data-structures"><span
|
||
class="toc-section-number">4.6</span> More Data Structures</a></li>
|
||
<li><a href="#reading-docs" id="toc-reading-docs"><span
|
||
class="toc-section-number">4.7</span> Reading Docs</a></li>
|
||
<li><a href="#quiz-3" id="toc-quiz-3"><span
|
||
class="toc-section-number">4.8</span> Quiz</a></li>
|
||
<li><a href="#exercises-3" id="toc-exercises-3"><span
|
||
class="toc-section-number">4.9</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-5-you-need-string-for-a-knot"
|
||
id="toc-lecture-5-you-need-string-for-a-knot"><span
|
||
class="toc-section-number">5</span> Lecture 5: You Need String for a
|
||
Knot</a>
|
||
<ul>
|
||
<li><a href="#algebraic-datatypes" id="toc-algebraic-datatypes"><span
|
||
class="toc-section-number">5.1</span> Algebraic Datatypes</a></li>
|
||
<li><a href="#type-parameters" id="toc-type-parameters"><span
|
||
class="toc-section-number">5.2</span> Type Parameters</a></li>
|
||
<li><a href="#recursive-types" id="toc-recursive-types"><span
|
||
class="toc-section-number">5.3</span> Recursive Types</a></li>
|
||
<li><a href="#record-syntax" id="toc-record-syntax"><span
|
||
class="toc-section-number">5.4</span> Record Syntax</a></li>
|
||
<li><a href="#algebraic-datatypes-summary"
|
||
id="toc-algebraic-datatypes-summary"><span
|
||
class="toc-section-number">5.5</span> Algebraic Datatypes:
|
||
Summary</a></li>
|
||
<li><a href="#sidenote-other-ways-of-defining-types"
|
||
id="toc-sidenote-other-ways-of-defining-types"><span
|
||
class="toc-section-number">5.6</span> Sidenote: Other Ways of Defining
|
||
Types</a></li>
|
||
<li><a href="#how-do-algebraic-datatypes-work"
|
||
id="toc-how-do-algebraic-datatypes-work"><span
|
||
class="toc-section-number">5.7</span> How Do Algebraic Datatypes
|
||
Work?</a></li>
|
||
<li><a href="#quiz-4" id="toc-quiz-4"><span
|
||
class="toc-section-number">5.8</span> Quiz</a></li>
|
||
<li><a href="#exercises-4" id="toc-exercises-4"><span
|
||
class="toc-section-number">5.9</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-6-working-class-hero"
|
||
id="toc-lecture-6-working-class-hero"><span
|
||
class="toc-section-number">6</span> Lecture 6: Working Class Hero</a>
|
||
<ul>
|
||
<li><a href="#syntax-of-classes-and-instances"
|
||
id="toc-syntax-of-classes-and-instances"><span
|
||
class="toc-section-number">6.1</span> Syntax of Classes and
|
||
Instances</a></li>
|
||
<li><a href="#default-implementations"
|
||
id="toc-default-implementations"><span
|
||
class="toc-section-number">6.2</span> Default Implementations</a></li>
|
||
<li><a href="#useful-stuff" id="toc-useful-stuff"><span
|
||
class="toc-section-number">6.3</span> Useful Stuff</a></li>
|
||
<li><a href="#hierarchies" id="toc-hierarchies"><span
|
||
class="toc-section-number">6.4</span> Hierarchies</a></li>
|
||
<li><a href="#quiz-5" id="toc-quiz-5"><span
|
||
class="toc-section-number">6.5</span> Quiz</a></li>
|
||
<li><a href="#exercises-5" id="toc-exercises-5"><span
|
||
class="toc-section-number">6.6</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-7-new-constellations"
|
||
id="toc-lecture-7-new-constellations"><span
|
||
class="toc-section-number">7</span> Lecture 7: New Constellations</a>
|
||
<ul>
|
||
<li><a href="#modeling-with-boxes" id="toc-modeling-with-boxes"><span
|
||
class="toc-section-number">7.1</span> Modeling with Boxes</a></li>
|
||
<li><a href="#modeling-with-cases" id="toc-modeling-with-cases"><span
|
||
class="toc-section-number">7.2</span> Modeling with Cases</a></li>
|
||
<li><a href="#monoids" id="toc-monoids"><span
|
||
class="toc-section-number">7.3</span> Monoids</a></li>
|
||
<li><a href="#open-and-closed-abstractions"
|
||
id="toc-open-and-closed-abstractions"><span
|
||
class="toc-section-number">7.4</span> Open and Closed
|
||
Abstractions</a></li>
|
||
<li><a href="#modeling-with-languages"
|
||
id="toc-modeling-with-languages"><span
|
||
class="toc-section-number">7.5</span> Modeling with Languages</a></li>
|
||
<li><a href="#exercises-6" id="toc-exercises-6"><span
|
||
class="toc-section-number">7.6</span> Exercises</a></li>
|
||
</ul></li>
|
||
<li><a href="#lecture-8-the-aftertaste"
|
||
id="toc-lecture-8-the-aftertaste"><span
|
||
class="toc-section-number">8</span> Lecture 8: The Aftertaste</a>
|
||
<ul>
|
||
<li><a href="#a-taste-of-io" id="toc-a-taste-of-io"><span
|
||
class="toc-section-number">8.1</span> A Taste of IO</a></li>
|
||
<li><a href="#summary" id="toc-summary"><span
|
||
class="toc-section-number">8.2</span> Summary</a></li>
|
||
<li><a href="#what-next" id="toc-what-next"><span
|
||
class="toc-section-number">8.3</span> What Next?</a></li>
|
||
<li><a href="#final-project-graphics"
|
||
id="toc-final-project-graphics"><span
|
||
class="toc-section-number">8.4</span> Final Project: Graphics</a></li>
|
||
<li><a href="#acknowledgements" id="toc-acknowledgements"><span
|
||
class="toc-section-number">8.5</span> Acknowledgements</a></li>
|
||
</ul></li>
|
||
</ul>
|
||
</nav>
|
||
<div id="text-container">
|
||
<div id="text">
|
||
<!-- MENU -->
|
||
<header>
|
||
<h1 class="title">Haskell Mooc, part 1</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="1" id="lecture-1-and-so-it-begins"><span
|
||
class="header-section-number">1</span> Lecture 1: …And so It Begins</h1>
|
||
<h2 data-number="1.1" id="about-the-course"><span
|
||
class="header-section-number">1.1</span> About the Course</h2>
|
||
<p>This is an online course on Functional Programming that uses the
|
||
Haskell programming language. You can study at your own pace. All the
|
||
material and exercises are openly available.</p>
|
||
<p>This course is aimed at beginners who wish to learn functional
|
||
programming, but also people who have experience with functional
|
||
programming and want to learn Haskell in particular. The course assumes
|
||
no previous knowledge, but knowing at least one programming language
|
||
beforehand will make the course easier.</p>
|
||
<p>Working on the exercises involves knowing how to use the command
|
||
line, and basic usage of the Git version control system.</p>
|
||
<p>This is part 1 of a two-part course. Part 1 covers the basics of
|
||
Haskell syntax and features. You will learn about recursion,
|
||
higher-order functions, algebraic data types and some of Haskell’s
|
||
advanced features. However, part 1 will stick to pure functional
|
||
programming, without side-effects. I/O and Monads will be introduced in
|
||
part 2.</p>
|
||
<p>The course is split into 8 lectures. They are roughly the same size,
|
||
but some lectures have more material than others. Each lecture set ends
|
||
with 10-30 small programming exercises on the topics of the lecture.</p>
|
||
<h2 data-number="1.2" id="read-these"><span
|
||
class="header-section-number">1.2</span> Read These</h2>
|
||
<p>In addition to this course material, the following sources might be
|
||
useful if you feel like you’re missing examples or explanations.</p>
|
||
<ul>
|
||
<li><a href="https://haskell.mooc.fi">The course pages</a></li>
|
||
<li>The course <a href="https://t.me/haskell_mooc_fi">channel on
|
||
Telegram</a></li>
|
||
<li>The course <a
|
||
href="https://github.com/moocfi/haskell-mooc">repository on Github</a>
|
||
contains the exercises and this material</li>
|
||
<li>Additional resources
|
||
<ul>
|
||
<li><a href="https://www.haskell.org/tutorial/">A Gentle Introduction to
|
||
Haskell</a> - an older and shorter tutorial, but still worth
|
||
reading</li>
|
||
<li><a href="http://learnyouahaskell.com/chapters">Learn You a Haskell
|
||
for Great Good!</a> – a nice free introduction to Haskell</li>
|
||
<li><a href="https://www.cs.yale.edu/homes/hudak/SOE/index.htm">The
|
||
Haskell School of Expression</a> - slightly older but still relevant
|
||
introduction to functional programming</li>
|
||
<li><a href="https://haskellbook.com/">Haskell Programming from First
|
||
Principles</a> - $59 e-book on Haskell, slow and long</li>
|
||
<li>The IRC channel <code>#haskell</code> on <a
|
||
href="https://libera.chat/">libera.chat</a> is a nice place for
|
||
beginners</li>
|
||
</ul></li>
|
||
</ul>
|
||
<h2 data-number="1.3" id="haskell"><span
|
||
class="header-section-number">1.3</span> Haskell</h2>
|
||
<p>Haskell is</p>
|
||
<p><strong>Functional</strong> – the basic building blocks of programs
|
||
are functions. Functions can return functions and take functions as
|
||
arguments. Also, the only looping construct in Haskell is recursion.</p>
|
||
<p><strong>Pure</strong> - Haskell functions are pure, that is, they
|
||
don’t have side effects. Side effects mean things like reading a file,
|
||
printing out text, or changing global variables. All inputs to a
|
||
function must be in its arguments, and all outputs from a function in
|
||
its return value. This sounds restricting, but makes reasoning about
|
||
programs easier, and allows for more optimizations by the compiler.</p>
|
||
<p><strong>Lazy</strong> - values are only evaluated when they are
|
||
needed. This makes it possible to work with infinite data structures,
|
||
and also makes pure programs more efficient.</p>
|
||
<p><strong>Strongly typed</strong> - every Haskell value and expression
|
||
has a type. The compiler checks the types at compile-time and guarantees
|
||
that no type errors can happen at runtime. This means no AttributeErrors
|
||
(a la Python), ClassCastExceptions (a la Java) or segmentation faults (a
|
||
la C). The Haskell type system is very powerful and can help you design
|
||
better programs.</p>
|
||
<p><strong>Type inferred</strong> - in addition to checking the types,
|
||
the compiler can deduce the types for most programs. This makes working
|
||
with a strongly typed language easier. Indeed, most Haskell functions
|
||
can be written completely without types. However programmers can still
|
||
give functions and values type annotations to make finding type errors
|
||
easier. Type annotations also make reading programs easier.</p>
|
||
<p><strong>Garbage-collected</strong> - like most high-level languages
|
||
these days, Haskell has automatic memory management via garbage
|
||
collection. This means that the programmer doesn’t need to worry about
|
||
allocating or freeing memory, the language runtime handles all of it
|
||
automatically.</p>
|
||
<p><strong>Compiled</strong> - even though we mostly use Haskell via the
|
||
interactive GHCi environment on this course, Haskell is a compiled
|
||
language. Haskell programs can be compiled to very efficient binaries,
|
||
and the GHC compiler is very good at optimising functional code into
|
||
performant machine code.</p>
|
||
<p>You’ll learn what these terms mean in practice during this course.
|
||
Don’t worry if some of them sound abstract right now.</p>
|
||
<p>See also: <a
|
||
href="https://wiki.haskell.org/Functional_programming">The Haskell Wiki
|
||
page on Functional programming</a>.</p>
|
||
<h3 data-number="1.3.1" id="features"><span
|
||
class="header-section-number">1.3.1</span> Features</h3>
|
||
<p>Here’s a showcase of some of the Haskell’s cool features:</p>
|
||
<p><strong>Higher-order functions</strong> – functions can take
|
||
functions as arguments:</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="fu">map</span> <span class="fu">length</span> [<span class="st">"abc"</span>,<span class="st">"abcdef"</span>]</span></code></pre></div>
|
||
<p>This results in <code>[3,6]</code>.</p>
|
||
<p><strong>Anonymous functions aka lambdas</strong> – you can define
|
||
single-use helper functions without giving them a name</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><span class="fu">filter</span> (\x <span class="ot">-></span> <span class="fu">length</span> x <span class="op">></span> <span class="dv">1</span>) [<span class="st">"abc"</span>,<span class="st">"d"</span>,<span class="st">"ef"</span>]</span></code></pre></div>
|
||
<p>This results in <code>["abc","ef"]</code>.</p>
|
||
<p><strong>Partial application</strong> – you can define new functions
|
||
by giving another function only some of the arguments it needs. For
|
||
example this multiplies all elements in a list by 3:</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="fu">map</span> (<span class="op">*</span><span class="dv">3</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p><strong>Algebraic datatypes</strong> – a syntax for defining
|
||
datatypes that can contain a number of different cases:</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="kw">data</span> <span class="dt">Shape</span> <span class="ot">=</span> <span class="dt">Point</span> <span class="op">|</span> <span class="dt">Rectangle</span> <span class="dt">Double</span> <span class="dt">Double</span> <span class="op">|</span> <span class="dt">Circle</span> <span class="dt">Double</span></span></code></pre></div>
|
||
<p>Now the type <code>Shape</code> can have values like
|
||
<code>Point</code>, <code>Rectangle 3 6</code> and
|
||
<code>Circle 5</code></p>
|
||
<p><strong>Pattern matching</strong> – defining functions based on cases
|
||
that correspond to your data definitions:</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>area <span class="dt">Point</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>area (<span class="dt">Rectangle</span> width height) <span class="ot">=</span> width <span class="op">*</span> height</span>
|
||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>area (<span class="dt">Circle</span> radius) <span class="ot">=</span> <span class="fu">pi</span> <span class="op">*</span> radius <span class="op">*</span> radius</span></code></pre></div>
|
||
<p><strong>Lists</strong> – Unlike many languages, Haskell has a concise
|
||
built-in syntax for lists. Lists can be built from other lists using
|
||
<em>list comprehensions</em>. Here’s a snippet that generates names of
|
||
even length from a set of options for first and last names:</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>[whole <span class="op">|</span> first <span class="ot"><-</span> [<span class="st">"Eva"</span>, <span class="st">"Mike"</span>],</span>
|
||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">last</span> <span class="ot"><-</span> [<span class="st">"Smith"</span>, <span class="st">"Wood"</span>, <span class="st">"Odd"</span>],</span>
|
||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">let</span> whole <span class="ot">=</span> first <span class="op">++</span> <span class="fu">last</span>,</span>
|
||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">even</span> (<span class="fu">length</span> whole)]</span></code></pre></div>
|
||
<p>This results in <code>["EvaSmith","EvaOdd","MikeWood"]</code>. Thanks
|
||
to the laziness of Haskell, we can even create so-called <em>infinite
|
||
lists</em>:</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>primes <span class="ot">=</span> [ n <span class="op">|</span> n <span class="ot"><-</span> [<span class="dv">2</span><span class="op">..</span>] , <span class="fu">all</span> (\k <span class="ot">-></span> n <span class="ot">`mod`</span> k <span class="op">/=</span> <span class="dv">0</span>) [<span class="dv">2</span><span class="op">..</span>n <span class="ot">`div`</span> <span class="dv">2</span>] ]</span></code></pre></div>
|
||
<p>The first ten prime numbers can be then obtained by evaluating</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="fu">take</span> <span class="dv">10</span> primes</span></code></pre></div>
|
||
<p>This evaluates to <code>[2,3,5,7,11,13,17,19,23,29]</code>.</p>
|
||
<p><strong>Parameterized types</strong> – you can define types that are
|
||
parameterized by other types. For example <code>[Int]</code> is a list
|
||
of <code>Int</code>s and <code>[Bool]</code> is a list of booleans. You
|
||
can define typed functions that work on all kinds of lists, for example
|
||
<code>reverse</code> has the type <code>[a] -> [a]</code> which means
|
||
it takes a list containing any type <code>a</code>, and returns a list
|
||
of the same type.</p>
|
||
<p><strong>Type classes</strong> – another form of polymorphism where
|
||
you can give a function a different implementation depending on the
|
||
arguments’ types. For example the <code>Show</code> type class defines
|
||
the function <code>show</code> that can convert values of various types
|
||
to strings. The <code>Num</code> type class defines arithmetic operators
|
||
like <code>+</code> that work on all number types (<code>Int</code>,
|
||
<code>Double</code>, <code>Complex</code>, …).</p>
|
||
<h3 data-number="1.3.2" id="some-history"><span
|
||
class="header-section-number">1.3.2</span> Some History</h3>
|
||
<p>A brief timeline of Haskell:</p>
|
||
<ul>
|
||
<li>1930s: Lambda Calculus</li>
|
||
<li>1950s-1970s: Lisp, Pattern Matching, Scheme, ML</li>
|
||
<li>1978 John Backus: <a
|
||
href="https://dl.acm.org/doi/pdf/10.1145/359576.359579">Can programming
|
||
be liberated from the von Neumann style?</a></li>
|
||
<li>1987 A decision was made to unify the field of pure functional
|
||
languages</li>
|
||
<li>1990 Haskell 1.0</li>
|
||
<li>1991 Haskell 1.1 (let-syntax, sections)</li>
|
||
<li>1992 Haskell 1.2, GHC</li>
|
||
<li>1996 Haskell 1.3 (Monads, do-syntax, type system improvements)</li>
|
||
<li>1999 Haskell 98</li>
|
||
<li>2000’s: GHC development, many extensions to the language</li>
|
||
<li>2009 <a href="https://www.haskell.org/onlinereport/haskell2010/">The
|
||
Haskell 2010 standard</a></li>
|
||
<li>2010’s: GHC development, Haskell Platform, Haskell Stack</li>
|
||
</ul>
|
||
<p>The word ‘haskel’ means wisdom in Hebrew, but the name of the Haskell
|
||
programming language comes from the logician Haskell Curry. The name
|
||
Haskell comes from the Old Norse words áss (god) and ketill
|
||
(helmet).</p>
|
||
<h3 data-number="1.3.3" id="uses-of-haskell"><span
|
||
class="header-section-number">1.3.3</span> Uses of Haskell</h3>
|
||
<p>Here are some examples of software projects that were written in
|
||
Haskell.</p>
|
||
<ul>
|
||
<li>The <a href="https://en.wikipedia.org/wiki/Darcs">Darcs</a>
|
||
distributed version control system</li>
|
||
<li>The <a
|
||
href="https://engineering.fb.com/security/fighting-spam-with-haskell/">Sigma
|
||
spam-prevention tool at Facebook</a></li>
|
||
<li>The implementations of the <a
|
||
href="https://www.purescript.org/">PureScript</a> and <a
|
||
href="https://elm-lang.org/">Elm</a> programming languages are written
|
||
in Haskell</li>
|
||
<li>The <a href="https://pandoc.org/">Pandoc</a> tool for converting
|
||
between different document formats – it’s also used to produce this
|
||
course material</li>
|
||
<li>The <a href="https://postgrest.org/">PostgREST</a> server that
|
||
exposes a HTTP REST API for a PostgreSQL database</li>
|
||
<li>Functional consulting companies like <a
|
||
href="https://galois.com/">Galois</a> and <a
|
||
href="https://well-typed.com/">Well-Typed</a> have a long history of
|
||
developing critical systems for clients in Haskell</li>
|
||
</ul>
|
||
<p>See <a href="https://wiki.haskell.org/Haskell_in_industry">The
|
||
Haskell Wiki</a> and <a
|
||
href="https://serokell.io/blog/top-software-written-in-haskell">this
|
||
blog post</a> for more!</p>
|
||
<h2 data-number="1.4" id="running-haskell"><span
|
||
class="header-section-number">1.4</span> Running Haskell</h2>
|
||
<p>The easiest way to get Haskell is to install the <code>stack</code>
|
||
tool, see <a href="https://haskellstack.org"
|
||
class="uri">https://haskellstack.org</a>. The exercises on this course
|
||
are intended to work with Stack, so you should use it for now.</p>
|
||
<p>By the way, if you’re interested in what Stack is, and how it relates
|
||
to other Haskell tools like Cabal and GHC, <a
|
||
href="https://www.quora.com/What-is-the-difference-between-Cabal-and-Stack-in-Haskell-projects-Which-one-do-you-recommend-and-why">read
|
||
more here</a> or <a
|
||
href="https://docs.haskellstack.org/en/stable/faq/">here</a>. We’ll get
|
||
back to Haskell packages and using them in detail in part 2 of the
|
||
course.</p>
|
||
<p>For now, after installing Stack, just run <code>stack ghci</code> to
|
||
get an interactive Haskell environment.</p>
|
||
<p><strong>Note!</strong> GHC 8.10.7 has a GHCi bug that makes editing
|
||
lines impossible on ARM-based systems. As a workaround, use
|
||
<code>TERM=dumb stack ghci</code>. More info <a
|
||
href="https://gitlab.haskell.org/ghc/ghc/-/issues/20022">here</a>.</p>
|
||
<h2 data-number="1.5" id="lets-start"><span
|
||
class="header-section-number">1.5</span> Let’s Start!</h2>
|
||
<p>GHCi is the interactive Haskell interpreter. Here’s an example
|
||
session:</p>
|
||
<pre><code>$ stack ghci
|
||
GHCi, version 9.2.8: https://www.haskell.org/ghc/ :? for help
|
||
Prelude> 1+1
|
||
2
|
||
Prelude> "asdf"
|
||
"asdf"
|
||
Prelude> reverse "asdf"
|
||
"fdsa"
|
||
Prelude> :type "asdf"
|
||
"asdf" :: [Char]
|
||
Prelude> tail "asdf"
|
||
"sdf"
|
||
Prelude> :type tail "asdf"
|
||
tail "asdf" :: [Char]
|
||
Prelude> :type tail
|
||
tail :: [a] -> [a]
|
||
Prelude> :quit
|
||
Leaving GHCi.</code></pre>
|
||
<p>By the way, the first time you run <code>stack ghci</code> it will
|
||
download GHC and some libraries, so don’t worry if you see some output
|
||
and have to wait for a while before getting the <code>Prelude></code>
|
||
prompt.</p>
|
||
<p>Let’s walk through this. Don’t worry if you don’t understand things
|
||
yet, this is just a first brush with expressions and types.</p>
|
||
<pre><code>Prelude> 1+1
|
||
2</code></pre>
|
||
<p>The <code>Prelude></code> is the GHCi prompt. It indicates we can
|
||
use the functions from the Haskell base library called Prelude. We
|
||
evaluate 1 plus 1, and the result is 2.</p>
|
||
<pre><code>Prelude> "asdf"
|
||
"asdf"</code></pre>
|
||
<p>Here we evaluate a string literal, and the result is the same
|
||
string.</p>
|
||
<pre><code>Prelude> reverse "asdf"
|
||
"fdsa"</code></pre>
|
||
<p>Here we compute the reverse of a string by applying the function
|
||
<code>reverse</code> to the value <code>"asdf"</code>.</p>
|
||
<pre><code>Prelude> :type "asdf"
|
||
"asdf" :: [Char]</code></pre>
|
||
<p>In addition to evaluating expressions we can also ask for their type
|
||
with the <code>:type</code> (abbreviated <code>:t</code>) GHCi command.
|
||
The type of <code>"asdf"</code> is a list of characters. Commands that
|
||
start with <code>:</code> are part of the user interface of GHCi, not
|
||
part of the Haskell language.</p>
|
||
<pre><code>Prelude> tail "asdf"
|
||
"sdf"
|
||
Prelude> :t tail "asdf"
|
||
tail "asdf" :: [Char]</code></pre>
|
||
<p>The <code>tail</code> function works on lists and returns all except
|
||
the first element of the list. Here we see <code>tail</code> applied to
|
||
<code>"asdf"</code>. We also check the type of the expression, and it is
|
||
a list of characters, as expected.</p>
|
||
<pre><code>Prelude> :t tail
|
||
tail :: [a] -> [a]</code></pre>
|
||
<p>Finally, here’s the type of the <code>tail</code> function. It takes
|
||
a list of any type as an argument, and returns a list of the same
|
||
type.</p>
|
||
<pre><code>Prelude> :quit
|
||
Leaving GHCi.</code></pre>
|
||
<p>That’s how you quit GHCi.</p>
|
||
<h2 data-number="1.6" id="expressions-and-types"><span
|
||
class="header-section-number">1.6</span> Expressions and Types</h2>
|
||
<p>Just like we saw in the GHCi example above, <em>expressions</em> and
|
||
<em>types</em> are the bread and butter of Haskell. In fact, almost
|
||
everything in a Haskell program is an expression. In particular, there
|
||
are no <em>statements</em> like in Python, Java or C.</p>
|
||
<p>An expression has a <em>value</em> and a <em>type</em>. We write an
|
||
expression and its type like this: <code>expression :: type</code>. Here
|
||
are some examples:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Expression</th>
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>True</code></td>
|
||
<td style="text-align: left;"><code>Bool</code></td>
|
||
<td style="text-align: left;"><code>True</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>not True</code></td>
|
||
<td style="text-align: left;"><code>Bool</code></td>
|
||
<td style="text-align: left;"><code>False</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>"as" ++ "df"</code></td>
|
||
<td style="text-align: left;"><code>[Char]</code></td>
|
||
<td style="text-align: left;"><code>"asdf"</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<h3 data-number="1.6.1" id="syntax-of-expressions"><span
|
||
class="header-section-number">1.6.1</span> Syntax of Expressions</h3>
|
||
<p>Expressions consist of functions <em>applied</em> to arguments.
|
||
Functions are <em>applied</em> (i.e. called) by placing the arguments
|
||
after the name of the function – there is no special syntax for a
|
||
function call.</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Haskell</th>
|
||
<th style="text-align: left;">Python, Java or C</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>f 1</code></td>
|
||
<td style="text-align: left;"><code>f(1)</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>f 1 2</code></td>
|
||
<td style="text-align: left;"><code>f(1,2)</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Parentheses can be used to <em>group</em> expressions (just like in
|
||
math and other languages).</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Haskell</th>
|
||
<th style="text-align: left;">Python, Java or C</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>g h f 1</code></td>
|
||
<td style="text-align: left;"><code>g(h,f,1)</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>g h (f 1)</code></td>
|
||
<td style="text-align: left;"><code>g(h,f(1))</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>g (h f 1)</code></td>
|
||
<td style="text-align: left;"><code>g(h(f,1))</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>g (h (f 1))</code></td>
|
||
<td style="text-align: left;"><code>g(h(f(1)))</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Some function names are made special characters and they are used as
|
||
operators: between their arguments instead of before them. Function
|
||
calls <em>bind tighter</em> than operators, just like multiplication
|
||
binds tighter than addition.</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Haskell</th>
|
||
<th style="text-align: left;">Python, Java or C</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>a + b</code></td>
|
||
<td style="text-align: left;"><code>a + b</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>f a + g b</code></td>
|
||
<td style="text-align: left;"><code>f(a) + g(b)</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>f (a + g b)</code></td>
|
||
<td style="text-align: left;"><code>f(a+g(b))</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>PS. in Haskell, function application <em>associates left</em>, that
|
||
is, <code>f g x y</code> is actually the same as
|
||
<code>(((f g) x) y)</code>. We’ll get back to this topic later. For now
|
||
you can just think that <code>f g x y</code> is <code>f</code> applied
|
||
to the arguments <code>g</code>, <code>x</code> and <code>y</code>.</p>
|
||
<h3 data-number="1.6.2" id="syntax-of-types"><span
|
||
class="header-section-number">1.6.2</span> Syntax of Types</h3>
|
||
<p>Here are some basic types of Haskell to get you started.</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Literals</th>
|
||
<th style="text-align: left;">Use</th>
|
||
<th style="text-align: left;">Operations</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Int</code></td>
|
||
<td style="text-align: left;"><code>1</code>, <code>2</code>,
|
||
<code>-3</code></td>
|
||
<td style="text-align: left;">Number type (signed, 64bit)</td>
|
||
<td style="text-align: left;"><code>+</code>, <code>-</code>,
|
||
<code>*</code>, <code>div</code>, <code>mod</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Integer</code></td>
|
||
<td style="text-align: left;"><code>1</code>, <code>-2</code>,
|
||
<code>900000000000000000</code></td>
|
||
<td style="text-align: left;">Unbounded number type</td>
|
||
<td style="text-align: left;"><code>+</code>, <code>-</code>,
|
||
<code>*</code>, <code>div</code>, <code>mod</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Double</code></td>
|
||
<td style="text-align: left;"><code>0.1</code>, <code>1.2e5</code></td>
|
||
<td style="text-align: left;">Floating point numbers</td>
|
||
<td style="text-align: left;"><code>+</code>, <code>-</code>,
|
||
<code>*</code>, <code>/</code>, <code>sqrt</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Bool</code></td>
|
||
<td style="text-align: left;"><code>True</code>, <code>False</code></td>
|
||
<td style="text-align: left;">Truth values</td>
|
||
<td style="text-align: left;"><code>&&</code>, <code>||</code>,
|
||
<code>not</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>String</code> aka
|
||
<code>[Char]</code></td>
|
||
<td style="text-align: left;"><code>"abcd"</code>, <code>""</code></td>
|
||
<td style="text-align: left;">Strings of characters</td>
|
||
<td style="text-align: left;"><code>reverse</code>, <code>++</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>As you can see, the names of types in Haskell start with a capital
|
||
letter. Some values like <code>True</code> also start with a capital
|
||
letter, but variables and functions start with a lower case letter
|
||
(<code>reverse</code>, <code>not</code>, <code>x</code>). We’ll get back
|
||
to the meaning of capital letters in Lecture 2.</p>
|
||
<p>Function types are written using the <code>-></code> syntax:</p>
|
||
<ul>
|
||
<li>A function of one argument:
|
||
<code>argumentType -> returnType</code></li>
|
||
<li>… of two arguments:
|
||
<code>argument1Type -> argument2Type -> returnType</code></li>
|
||
<li>… of three arguments:
|
||
<code>argument1Type -> argument2Type -> argument3Type -> returnType</code></li>
|
||
</ul>
|
||
<p>Looks a bit weird, right? We’ll get back to this as well.</p>
|
||
<h3 data-number="1.6.3" id="note-about-misleading-types"><span
|
||
class="header-section-number">1.6.3</span> Note About Misleading
|
||
Types</h3>
|
||
<p>Sometimes, the types you see in GHCi are a bit different than what
|
||
you’d assume. Here are two common cases.</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dv">1</span><span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span><span class="op">+</span><span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a</span></code></pre></div>
|
||
<p>For now, you should read the type <code>Num a => a</code> as “any
|
||
number type”. In Haskell, number literals are <em>overloaded</em> which
|
||
means that they can be interpreted as any number type
|
||
(e.g. <code>Int</code> or <code>Double</code>). We’ll get back to what
|
||
<code>Num a</code> actually means when we talk about <em>type
|
||
classes</em> later.</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="st">"asdf"</span></span>
|
||
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="st">"asdf"</span><span class="ot"> ::</span> [<span class="dt">Char</span>]</span></code></pre></div>
|
||
<p>The type <code>String</code> is just an alias for the type
|
||
<code>[Char]</code> which means “list of characters”. We’ll get back to
|
||
lists on the next lecture! In any case, you can use <code>String</code>
|
||
and <code>[Char]</code> interchangeably, but GHCi will mostly use
|
||
<code>[Char]</code> when describing types to you.</p>
|
||
<h2 data-number="1.7" id="the-structure-of-a-haskell-program"><span
|
||
class="header-section-number">1.7</span> The Structure of a Haskell
|
||
Program</h2>
|
||
<p>Here’s a simple Haskell program that does some arithmetic and prints
|
||
some values.</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="kw">module</span> <span class="dt">Gold</span> <span class="kw">where</span></span>
|
||
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- The golden ratio</span></span>
|
||
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="ot">phi ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>phi <span class="ot">=</span> (<span class="fu">sqrt</span> <span class="dv">5</span> <span class="op">+</span> <span class="dv">1</span>) <span class="op">/</span> <span class="dv">2</span></span>
|
||
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a><span class="ot">polynomial ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>polynomial x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x <span class="op">-</span> <span class="dv">1</span></span>
|
||
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> polynomial (polynomial x)</span>
|
||
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (polynomial phi)</span>
|
||
<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (f phi)</span></code></pre></div>
|
||
<p>If you put this in a file called <code>Gold.hs</code> and run it with
|
||
(for example) <code>stack runhaskell Gold.hs</code>, you should see this
|
||
output</p>
|
||
<pre><code>0.0
|
||
-1.0</code></pre>
|
||
<p>Let’s walk through the file.</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="kw">module</span> <span class="dt">Gold</span> <span class="kw">where</span></span></code></pre></div>
|
||
<p>There is one Haskell <em>module</em> per source file. A module
|
||
consists of <em>definitions</em>.</p>
|
||
<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><span class="co">-- The golden ratio</span></span></code></pre></div>
|
||
<p>This is a comment. Comments are not part of the actual program, but
|
||
text for human readers of the program.</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="ot">phi ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a>phi <span class="ot">=</span> (<span class="fu">sqrt</span> <span class="dv">5</span> <span class="op">+</span> <span class="dv">1</span>) <span class="op">/</span> <span class="dv">2</span></span></code></pre></div>
|
||
<p>This is a definition of the constant <code>phi</code>, with an
|
||
accompanying <em>type annotation</em> (also known as a <em>type
|
||
signature</em>) <code>phi :: Double</code>. The type annotation means
|
||
that <code>phi</code> has type <code>Double</code>. The line with a
|
||
equals sign (<code>=</code>) is called an <em>equation</em>. The left
|
||
hand side of the <code>=</code> is the expression we are defining, and
|
||
the right hand side of the <code>=</code> is the definition.</p>
|
||
<p>In general a definition (of a function or constant) consists of an
|
||
optional <em>type annotation</em> and one or more <em>equations</em></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="ot">polynomial ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a>polynomial x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x <span class="op">-</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>This is the definition of a function called <code>polynomial</code>.
|
||
It has a type annotation and an equation. Note how an equation for a
|
||
function differs from the equation of a constant by the presence of a
|
||
parameter <code>x</code> left of the <code>=</code> sign. Note also that
|
||
<code>^</code> is the power operator in Haskell, not bitwise xor like in
|
||
many other languages.</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>f x <span class="ot">=</span> polynomial (polynomial x)</span></code></pre></div>
|
||
<p>This is the definition of a function called <code>f</code>. Note the
|
||
lack of type annotation. What is the type of <code>f</code>?</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>main <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (polynomial phi)</span>
|
||
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (f phi)</span></code></pre></div>
|
||
<p>This is a description of what happens when you run the program. It
|
||
uses do-syntax and the IO Monad. We’ll get back to those in part 2 of
|
||
the course.</p>
|
||
<h2 data-number="1.8" id="working-with-examples"><span
|
||
class="header-section-number">1.8</span> Working with Examples</h2>
|
||
<p>When you see an example definition like this</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="ot">polynomial ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>polynomial x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x <span class="op">-</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>you should usually play around with it. Start by running it. There
|
||
are a couple of ways to do this.</p>
|
||
<p>If a definition fits on one line, you can just define it in GHCi:</p>
|
||
<pre><code>Prelude> polynomial x = x^2 - x - 1
|
||
Prelude> polynomial 3.0
|
||
5.0</code></pre>
|
||
<p>For a multi-line definition, you can either use <code>;</code> to
|
||
separate lines, or use the special <code>:{ :}</code> syntax to paste a
|
||
block of code into GHCi:</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>{</span>
|
||
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">|</span><span class="ot"> polynomial ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">|</span> polynomial x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x <span class="op">-</span> <span class="dv">1</span></span>
|
||
<span id="cb29-4"><a href="#cb29-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">|</span> <span class="op">:</span>}</span>
|
||
<span id="cb29-5"><a href="#cb29-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> polynomial <span class="fl">3.0</span></span>
|
||
<span id="cb29-6"><a href="#cb29-6" aria-hidden="true" tabindex="-1"></a><span class="fl">5.0</span></span></code></pre></div>
|
||
<p>Finally, you can paste the code into a new or existing
|
||
<code>.hs</code> file, and then <code>:load</code> it into GHCi. If the
|
||
file has already been loaded, you can also use <code>:reload</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="co">-- first copy and paste the definition into Example.hs, then run GHCi</span></span>
|
||
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>load Example.hs</span>
|
||
<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span> <span class="kw">of</span> <span class="dv">1</span>] <span class="dt">Compiling</span> <span class="dt">Main</span> ( Example.hs, interpreted )</span>
|
||
<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Ok</span>, one <span class="kw">module</span> loaded<span class="op">.</span></span>
|
||
<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> polynomial <span class="fl">3.0</span></span>
|
||
<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a><span class="fl">5.0</span></span>
|
||
<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- now you can edit the definition</span></span>
|
||
<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> <span class="op">:</span>reload</span>
|
||
<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span> <span class="kw">of</span> <span class="dv">1</span>] <span class="dt">Compiling</span> <span class="dt">Main</span> ( Example.hs, interpreted )</span>
|
||
<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Ok</span>, one <span class="kw">module</span> loaded<span class="op">.</span></span>
|
||
<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> polynomial <span class="dv">3</span></span>
|
||
<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a><span class="fl">3.0</span></span></code></pre></div>
|
||
<p>After you’ve run the example, try modifying it, or making another
|
||
function that is similar but different. You learn programming by
|
||
programming, not by reading!</p>
|
||
<h3 data-number="1.8.1" id="dealing-with-errors"><span
|
||
class="header-section-number">1.8.1</span> Dealing with Errors</h3>
|
||
<p>Since Haskell is a typed language, you’ll pretty quickly bump into
|
||
type errors. Here’s an example of an error during a GHCi session:</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="dt">Prelude</span><span class="op">></span> <span class="st">"string"</span> <span class="op">++</span> <span class="dt">True</span></span>
|
||
<span id="cb31-2"><a href="#cb31-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb31-3"><a href="#cb31-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">13</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb31-4"><a href="#cb31-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘[<span class="dt">Char</span>]’ with actual <span class="kw">type</span> ‘<span class="dt">Bool</span>’</span>
|
||
<span id="cb31-5"><a href="#cb31-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">++</span>)’, namely ‘<span class="dt">True</span>’</span>
|
||
<span id="cb31-6"><a href="#cb31-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> <span class="st">"string"</span> <span class="op">++</span> <span class="dt">True</span></span>
|
||
<span id="cb31-7"><a href="#cb31-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> <span class="st">"string"</span> <span class="op">++</span> <span class="dt">True</span></span></code></pre></div>
|
||
<p>This is the most common type error, “Couldn’t match expected type”.
|
||
Even though the error looks long and scary, it’s pretty simple if you
|
||
just read through it.</p>
|
||
<ul>
|
||
<li><p>The first line of the error message,
|
||
<code><interactive>:1:13: error:</code> tells us that the error
|
||
occurred in GHCi. If we had loaded a file, we might instead get
|
||
something like <code>Sandbox.hs:3:17: error:</code>, where
|
||
<code>Sandbox.hs</code> is the name of the file, <code>3</code> is the
|
||
line number and <code>17</code> is the number of a character in the
|
||
line.</p></li>
|
||
<li><p>The line
|
||
<code>• Couldn't match expected type ‘[Char]’ with actual type ‘Bool’</code>
|
||
tells us that the immediate cause for the error is that there was an
|
||
expression of type <code>Bool</code>, when GHCi was expecting to find an
|
||
expression of type <code>[Char]</code>“. The location of this error was
|
||
indicated in the first line of the error message. Note that the expected
|
||
type is not always right. Giving type annotations by hand can help
|
||
debugging typing errors.</p></li>
|
||
<li><p>The line
|
||
<code>• In the second argument of ‘(++)’, namely ‘True’</code> tells
|
||
that the expression that had the wrong type was the second argument of
|
||
the operator <code>(++)</code>. We’ll learn later why it’s surrounded by
|
||
parentheses.</p></li>
|
||
<li><p>The full expression with the error was
|
||
<code>"string" ++ True</code>. As mentioned above, <code>String</code>
|
||
is a type alias for <code>[Char]</code>, the type of character lists.
|
||
The first argument to <code>++</code> was a list of characters, and
|
||
since <code>++</code> can only combine two lists of the same type, the
|
||
second argument should’ve been of type <code>[Char]</code> too.</p></li>
|
||
<li><p>The line
|
||
<code>In an equation for ‘it’: it = "string" ++ True</code> says that
|
||
the expression occurred in the definition of the variable
|
||
<code>it</code>, which is a default variable name that GHCi uses for
|
||
standalone expressions. If we had a line
|
||
<code>x = "string" ++ True</code> in a file, or a declaration
|
||
<code>let x = "string" ++ True</code> in GHCi, GHCi would print
|
||
<code>In an equation for ‘x’: x = "string" ++ True</code>
|
||
instead.</p></li>
|
||
</ul>
|
||
<p>There are also others types of errors.</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="dt">Prelude</span><span class="op">></span> <span class="dt">True</span> <span class="op">+</span> <span class="dv">1</span></span>
|
||
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb32-3"><a href="#cb32-3" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">6</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="cb32-4"><a href="#cb32-4" 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> ‘<span class="op">+</span>’</span>
|
||
<span id="cb32-5"><a href="#cb32-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the expression<span class="op">:</span> <span class="dt">True</span> <span class="op">+</span> <span class="dv">1</span></span>
|
||
<span id="cb32-6"><a href="#cb32-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> <span class="dt">True</span> <span class="op">+</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>This is the kind of error you get when you try to use a numeric
|
||
function like <code>+</code> on something that’s not a number.</p>
|
||
<p>The hardest error to track down is usually this:</p>
|
||
<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">Prelude</span><span class="op">></span> <span class="dt">True</span> <span class="op">+</span></span>
|
||
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">10</span><span class="op">:</span><span class="dv">7</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a> parse <span class="fu">error</span> (possibly incorrect indentation <span class="fu">or</span> mismatched brackets)</span></code></pre></div>
|
||
<p>There are many ways to cause it. Probably you’re missing some
|
||
characters somewhere. We’ll get back to indentation later in this
|
||
lecture.</p>
|
||
<!-- TODO more errors based on feedback -->
|
||
<h3 data-number="1.8.2" id="arithmetic"><span
|
||
class="header-section-number">1.8.2</span> Arithmetic</h3>
|
||
<p>There’s one thing in Haskell arithmetic that often trips up
|
||
beginners, and that’s division.</p>
|
||
<p>In Haskell there are two division functions, the <code>/</code>
|
||
operator and the <code>div</code> function. The <code>div</code>
|
||
function does integer division:</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="dt">Prelude</span><span class="op">></span> <span class="dv">7</span> <span class="ot">`div`</span> <span class="dv">2</span></span>
|
||
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></code></pre></div>
|
||
<p>The <code>/</code> operator performs the usual division:</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><span class="dt">Prelude</span><span class="op">></span> <span class="fl">7.0</span> <span class="op">/</span> <span class="fl">2.0</span></span>
|
||
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="fl">3.5</span></span></code></pre></div>
|
||
<p>However, you can only use <code>div</code> on whole number types like
|
||
<code>Int</code> and <code>Integer</code>, and you can only use
|
||
<code>/</code> on decimal types like <code>Double</code>. Here’s an
|
||
example of what happens if you try to mix them up:</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><span class="ot">halve ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>halve x <span class="ot">=</span> x <span class="op">/</span> <span class="dv">2</span></span></code></pre></div>
|
||
<pre><code>error:
|
||
• No instance for (Fractional Int) arising from a use of ‘/’
|
||
• In the expression: x / 2
|
||
In an equation for ‘halve’: halve x = x / 2</code></pre>
|
||
<p>Just try to keep this in mind for now. We’ll get back to the
|
||
difference between <code>/</code> and <code>div</code>, and what
|
||
<code>Num</code> and <code>Fractional</code> mean when talking about
|
||
type classes.</p>
|
||
<h2 data-number="1.9" id="how-do-i-get-anything-done"><span
|
||
class="header-section-number">1.9</span> How Do I Get Anything
|
||
Done?</h2>
|
||
<p>So far you’ve seen some arithmetic, reversing a string and so on. How
|
||
does one write actual programs in Haskell? Many of the usual programming
|
||
constructs like loops, statements and assignment are missing from
|
||
Haskell. Next, we’ll go through the basic building blocks of Haskell
|
||
programs:</p>
|
||
<ul>
|
||
<li>Conditionals</li>
|
||
<li>Local definitions</li>
|
||
<li>Pattern matching</li>
|
||
<li>Recursion</li>
|
||
</ul>
|
||
<h3 data-number="1.9.1" id="conditionals"><span
|
||
class="header-section-number">1.9.1</span> Conditionals</h3>
|
||
<p>In other languages, <code>if</code> is a <em>statement</em>. It
|
||
doesn’t have a value, it just conditionally executes other
|
||
statements.</p>
|
||
<p>In Haskell, <code>if</code> is an <em>expression</em>. It has a
|
||
value. It selects between two other expressions. It corresponds to the
|
||
<code>?:</code> operator in C or Java.</p>
|
||
<div class="sourceCode" id="cb38"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Java</span></span>
|
||
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> price <span class="op">=</span> product<span class="op">.</span><span class="fu">equals</span><span class="op">(</span><span class="st">"milk"</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></code></pre></div>
|
||
<p>Python’s conditional expressions are quite close to haskell’s
|
||
<code>if</code>:</p>
|
||
<div class="sourceCode" id="cb39"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Python</span></span>
|
||
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a>price <span class="op">=</span> <span class="dv">1</span> <span class="cf">if</span> product <span class="op">==</span> <span class="st">"milk"</span> <span class="cf">else</span> <span class="dv">2</span></span></code></pre></div>
|
||
<p>This is how the same example looks in Haskell:</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>price <span class="ot">=</span> <span class="kw">if</span> <span class="fu">product</span> <span class="op">==</span> <span class="st">"milk"</span> <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">2</span></span></code></pre></div>
|
||
<p>Because Haskell’s <code>if</code> <em>returns</em> a value, you
|
||
<strong>always</strong> need an <code>else</code>!</p>
|
||
<h4 data-number="1.9.1.1" id="functions-returning-bool"><span
|
||
class="header-section-number">1.9.1.1</span> Functions Returning
|
||
<code>Bool</code></h4>
|
||
<p>In order to write if expressions, you need to know how to get values
|
||
of type <code>Bool</code>. The most common way is comparisons. The usual
|
||
<code>==</code>, <code><</code>, <code><=</code>,
|
||
<code>></code> and <code>>=</code> operators work in Haskell. You
|
||
can do ordered comparisons (<code><</code>, <code>></code>) on all
|
||
sorts of numbers, and equality comparisons (<code>==</code>) on almost
|
||
anything:</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="dt">Prelude</span><span class="op">></span> <span class="st">"foo"</span> <span class="op">==</span> <span class="st">"bar"</span></span>
|
||
<span id="cb41-2"><a href="#cb41-2" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb41-3"><a href="#cb41-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fl">5.0</span> <span class="op"><=</span> <span class="fl">7.2</span></span>
|
||
<span id="cb41-4"><a href="#cb41-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb41-5"><a href="#cb41-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dv">1</span> <span class="op">==</span> <span class="dv">1</span></span>
|
||
<span id="cb41-6"><a href="#cb41-6" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<p>One oddity of Haskell is that the not-equals operator is written
|
||
<code>/=</code> instead of the usual <code>!=</code>:</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="dt">Prelude</span><span class="op">></span> <span class="dv">2</span> <span class="op">/=</span> <span class="dv">3</span></span>
|
||
<span id="cb42-2"><a href="#cb42-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb42-3"><a href="#cb42-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="st">"bike"</span> <span class="op">/=</span> <span class="st">"bike"</span></span>
|
||
<span id="cb42-4"><a href="#cb42-4" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></code></pre></div>
|
||
<p>Remember that in addition to these comparisons, you can get
|
||
<code>Bool</code> values out of other <code>Bool</code> values by using
|
||
the <code>&&</code> (“and”) and <code>||</code> (“or”)
|
||
operators, and the <code>not</code> function.</p>
|
||
<h4 data-number="1.9.1.2" id="examples"><span
|
||
class="header-section-number">1.9.1.2</span> Examples</h4>
|
||
<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>checkPassword password <span class="ot">=</span> <span class="kw">if</span> password <span class="op">==</span> <span class="st">"swordfish"</span></span>
|
||
<span id="cb43-2"><a href="#cb43-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="st">"You're in."</span></span>
|
||
<span id="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="st">"ACCESS DENIED!"</span></span></code></pre></div>
|
||
<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>absoluteValue n <span class="ot">=</span> <span class="kw">if</span> n <span class="op"><</span> <span class="dv">0</span> <span class="kw">then</span> <span class="op">-</span>n <span class="kw">else</span> n</span></code></pre></div>
|
||
<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>login user password <span class="ot">=</span> <span class="kw">if</span> user <span class="op">==</span> <span class="st">"unicorn73"</span></span>
|
||
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="kw">if</span> password <span class="op">==</span> <span class="st">"f4bulous!"</span></span>
|
||
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="st">"unicorn73 logged in"</span></span>
|
||
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="st">"wrong password"</span></span>
|
||
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="st">"unknown user"</span></span></code></pre></div>
|
||
<h3 data-number="1.9.2" id="local-definitions"><span
|
||
class="header-section-number">1.9.2</span> Local Definitions</h3>
|
||
<p>Haskell has two different ways for creating local definitions:
|
||
<code>let...in</code> and <code>where</code>.</p>
|
||
<p><code>where</code> adds local definitions to a definition:</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="ot">circleArea ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>circleArea r <span class="ot">=</span> <span class="fu">pi</span> <span class="op">*</span> rsquare</span>
|
||
<span id="cb46-3"><a href="#cb46-3" 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="cb46-4"><a href="#cb46-4" aria-hidden="true" tabindex="-1"></a> rsquare <span class="ot">=</span> r <span class="op">*</span> r</span></code></pre></div>
|
||
<p><code>let...in</code> is an expression:</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>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="cb47-2"><a href="#cb47-2" aria-hidden="true" tabindex="-1"></a> rsquare <span class="ot">=</span> r <span class="op">*</span> r</span>
|
||
<span id="cb47-3"><a href="#cb47-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">pi</span> <span class="op">*</span> rsquare</span></code></pre></div>
|
||
<p>Local definitions can also be functions:</p>
|
||
<div class="sourceCode" id="cb48"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb48-1"><a href="#cb48-1" 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="cb48-2"><a href="#cb48-2" 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="cb48-3"><a href="#cb48-3" aria-hidden="true" tabindex="-1"></a> square x <span class="ot">=</span> x <span class="op">*</span> x</span></code></pre></div>
|
||
<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>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="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a> square x <span class="ot">=</span> x <span class="op">*</span> x</span>
|
||
<span id="cb49-3"><a href="#cb49-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">pi</span> <span class="op">*</span> square r</span></code></pre></div>
|
||
<p>We’ll get back to the differences between <code>let</code> and
|
||
<code>where</code>, but mostly you can use which ever you like.</p>
|
||
<h3 data-number="1.9.3" id="a-word-about-immutability"><span
|
||
class="header-section-number">1.9.3</span> A Word About
|
||
Immutability</h3>
|
||
<p>Even though things like <code>pi</code> above are often called
|
||
<em>variables</em>, I’ve chosen to call them <em>definitions</em> here.
|
||
This is because unlike variables in Python or Java, the values of these
|
||
definitions can’t be changed. Haskell variables aren’t boxes into which
|
||
you can put new values, Haskell variables name a value (or rather, an
|
||
expression) and that’s it.</p>
|
||
<p>We’ll talk about immutability again later on this course, but for now
|
||
it’s enough to know that things like this don’t work.</p>
|
||
<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>increment x <span class="ot">=</span> <span class="kw">let</span> x <span class="ot">=</span> x<span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> x</span></code></pre></div>
|
||
<p>This is just an infinite loop, because it tries to define a new
|
||
variable <code>x</code> with the property <code>x = x+1</code>. Thus
|
||
when evaluating <code>x</code>, Haskell just keeps computing
|
||
<code>1+1+1+1+...</code> indefinitely.</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>compute x <span class="ot">=</span> <span class="kw">let</span> a <span class="ot">=</span> x<span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a> a <span class="ot">=</span> a<span class="op">*</span><span class="dv">2</span></span>
|
||
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> a</span></code></pre></div>
|
||
<pre><code>error:
|
||
Conflicting definitions for ‘a’
|
||
Bound at: <interactive>:14:17
|
||
<interactive>:15:17</code></pre>
|
||
<p>Here we get a straightforward error when we’re trying to “update” the
|
||
value of <code>a</code>.</p>
|
||
<p>As a remark, local definitions can <em>shadow</em> the names of
|
||
variables defined elsewhere. Shadowing is not a side-effect. Instead,
|
||
shadowing creates a new variable within a more restricted scope that
|
||
uses the same name as some variable in the outer scope. For example, all
|
||
of the functions <code>f</code>, <code>g</code>, and <code>h</code>
|
||
below are legal:</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">x ::</span> <span class="dt">Int</span></span>
|
||
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>x <span class="ot">=</span> <span class="dv">5</span></span>
|
||
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb53-4"><a href="#cb53-4" 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="cb53-5"><a href="#cb53-5" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> <span class="dv">2</span> <span class="op">*</span> x</span>
|
||
<span id="cb53-6"><a href="#cb53-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb53-7"><a href="#cb53-7" 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>
|
||
<span id="cb53-8"><a href="#cb53-8" aria-hidden="true" tabindex="-1"></a>g y <span class="ot">=</span> x <span class="kw">where</span> x <span class="ot">=</span> <span class="dv">6</span></span>
|
||
<span id="cb53-9"><a href="#cb53-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb53-10"><a href="#cb53-10" aria-hidden="true" tabindex="-1"></a><span class="ot">h ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb53-11"><a href="#cb53-11" aria-hidden="true" tabindex="-1"></a>h x <span class="ot">=</span> x <span class="kw">where</span> x <span class="ot">=</span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>If we apply them to the global constant <code>x</code>, we see the
|
||
effects of shadowing:</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="op">==></span> <span class="dv">2</span></span>
|
||
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a>g <span class="dv">1</span> <span class="op">==></span> <span class="dv">6</span></span>
|
||
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a>h <span class="dv">1</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb54-4"><a href="#cb54-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb54-5"><a href="#cb54-5" aria-hidden="true" tabindex="-1"></a>f x <span class="op">==></span> <span class="dv">10</span></span>
|
||
<span id="cb54-6"><a href="#cb54-6" aria-hidden="true" tabindex="-1"></a>g x <span class="op">==></span> <span class="dv">6</span></span>
|
||
<span id="cb54-7"><a href="#cb54-7" aria-hidden="true" tabindex="-1"></a>h x <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>It is best to always choose new names for local variables, so that
|
||
shadowing never happens. That way, the reader of the code will
|
||
understand where the variables that are used in an expression come from.
|
||
Note that in the following example, <code>f</code> and <code>g</code>
|
||
don’t shadow each others’ arguments:</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><span class="ot">f ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> <span class="dv">2</span> <span class="op">*</span> x <span class="op">+</span> <span class="dv">1</span></span>
|
||
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb55-4"><a href="#cb55-4" 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>
|
||
<span id="cb55-5"><a href="#cb55-5" aria-hidden="true" tabindex="-1"></a>g x <span class="ot">=</span> x <span class="op">-</span> <span class="dv">2</span></span></code></pre></div>
|
||
<h3 data-number="1.9.4" id="pattern-matching"><span
|
||
class="header-section-number">1.9.4</span> Pattern Matching</h3>
|
||
<p>A definition (of a function) can consist of multiple
|
||
<em>equations</em>. The equations are matched in order against the
|
||
arguments until a suitable one is found. This is called <em>pattern
|
||
matching</em>.</p>
|
||
<p>Pattern matching in Haskell is very powerful, and we’ll keep learning
|
||
new things about it along this course, but here are a couple of first
|
||
examples:</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="ot">greet ::</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="cb56-2"><a href="#cb56-2" aria-hidden="true" tabindex="-1"></a>greet <span class="st">"Finland"</span> name <span class="ot">=</span> <span class="st">"Hei, "</span> <span class="op">++</span> name</span>
|
||
<span id="cb56-3"><a href="#cb56-3" aria-hidden="true" tabindex="-1"></a>greet <span class="st">"Italy"</span> name <span class="ot">=</span> <span class="st">"Ciao, "</span> <span class="op">++</span> name</span>
|
||
<span id="cb56-4"><a href="#cb56-4" aria-hidden="true" tabindex="-1"></a>greet <span class="st">"England"</span> name <span class="ot">=</span> <span class="st">"How do you do, "</span> <span class="op">++</span> name</span>
|
||
<span id="cb56-5"><a href="#cb56-5" aria-hidden="true" tabindex="-1"></a>greet _ name <span class="ot">=</span> <span class="st">"Hello, "</span> <span class="op">++</span> name</span></code></pre></div>
|
||
<p>The function <code>greet</code> generates a greeting given a country
|
||
and a name (both <code>String</code>s). It has special cases for three
|
||
countries, and a default case. This is how it works:</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="dt">Prelude</span><span class="op">></span> greet <span class="st">"Finland"</span> <span class="st">"Pekka"</span></span>
|
||
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a><span class="st">"Hei, Pekka"</span></span>
|
||
<span id="cb57-3"><a href="#cb57-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> greet <span class="st">"England"</span> <span class="st">"Bob"</span></span>
|
||
<span id="cb57-4"><a href="#cb57-4" aria-hidden="true" tabindex="-1"></a><span class="st">"How do you do, Bob"</span></span>
|
||
<span id="cb57-5"><a href="#cb57-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> greet <span class="st">"Italy"</span> <span class="st">"Maria"</span></span>
|
||
<span id="cb57-6"><a href="#cb57-6" aria-hidden="true" tabindex="-1"></a><span class="st">"Ciao, Maria"</span></span>
|
||
<span id="cb57-7"><a href="#cb57-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> greet <span class="st">"Greenland"</span> <span class="st">"Jan"</span></span>
|
||
<span id="cb57-8"><a href="#cb57-8" aria-hidden="true" tabindex="-1"></a><span class="st">"Hello, Jan"</span></span></code></pre></div>
|
||
<p>The special pattern <code>_</code> matches anything. It’s usually
|
||
used for default cases. Because patterns are matched in order, it’s
|
||
important to (<em>usually</em>) put the <code>_</code> case last.
|
||
Consider:</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>brokenGreet _ name <span class="ot">=</span> <span class="st">"Hello, "</span> <span class="op">++</span> name</span>
|
||
<span id="cb58-2"><a href="#cb58-2" aria-hidden="true" tabindex="-1"></a>brokenGreet <span class="st">"Finland"</span> name <span class="ot">=</span> <span class="st">"Hei, "</span> <span class="op">++</span> name</span></code></pre></div>
|
||
<p>Now the first case gets selected for all inputs.</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><span class="dt">Prelude</span><span class="op">></span> brokenGreet <span class="st">"Finland"</span> <span class="st">"Varpu"</span></span>
|
||
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a><span class="st">"Hello, Varpu"</span></span>
|
||
<span id="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> brokenGreet <span class="st">"Sweden"</span> <span class="st">"Ole"</span></span>
|
||
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a><span class="st">"Hello, Ole"</span></span></code></pre></div>
|
||
<p>GHC even gives you a warning about this code:</p>
|
||
<pre><code><interactive>:1:1: warning: [-Woverlapping-patterns]
|
||
Pattern match is redundant
|
||
In an equation for ‘brokenGreet’: brokenGreet "Finland" name = ...</code></pre>
|
||
<p>Some more examples follow. But first let’s introduce the standard
|
||
library function <code>show</code> that can turn (almost!) anything into
|
||
a string:</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><span class="dt">Prelude</span><span class="op">></span> <span class="fu">show</span> <span class="dt">True</span></span>
|
||
<span id="cb61-2"><a href="#cb61-2" aria-hidden="true" tabindex="-1"></a><span class="st">"True"</span></span>
|
||
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">show</span> <span class="dv">3</span></span>
|
||
<span id="cb61-4"><a href="#cb61-4" aria-hidden="true" tabindex="-1"></a><span class="st">"3"</span></span></code></pre></div>
|
||
<p>So, here’s an example of a function with pattern matching and a
|
||
default case that actually uses the value (instead of just ignoring it
|
||
with <code>_</code>):</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">describe ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb62-2"><a href="#cb62-2" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">0</span> <span class="ot">=</span> <span class="st">"zero"</span></span>
|
||
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">1</span> <span class="ot">=</span> <span class="st">"one"</span></span>
|
||
<span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">2</span> <span class="ot">=</span> <span class="st">"an even prime"</span></span>
|
||
<span id="cb62-5"><a href="#cb62-5" aria-hidden="true" tabindex="-1"></a>describe n <span class="ot">=</span> <span class="st">"the number "</span> <span class="op">++</span> <span class="fu">show</span> n</span></code></pre></div>
|
||
<p>This is how it works:</p>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> describe <span class="dv">0</span></span>
|
||
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a><span class="st">"zero"</span></span>
|
||
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> describe <span class="dv">2</span></span>
|
||
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a><span class="st">"an even prime"</span></span>
|
||
<span id="cb63-5"><a href="#cb63-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> describe <span class="dv">7</span></span>
|
||
<span id="cb63-6"><a href="#cb63-6" aria-hidden="true" tabindex="-1"></a><span class="st">"the number 7"</span></span></code></pre></div>
|
||
<p>You can even pattern match on multiple arguments. Again, the
|
||
equations are tried in order. Here’s a reimplementation of the
|
||
<code>login</code> function from earlier:</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">login ::</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="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a>login <span class="st">"unicorn73"</span> <span class="st">"f4bulous!"</span> <span class="ot">=</span> <span class="st">"unicorn73 logged in"</span></span>
|
||
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>login <span class="st">"unicorn73"</span> _ <span class="ot">=</span> <span class="st">"wrong password"</span></span>
|
||
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a>login _ _ <span class="ot">=</span> <span class="st">"unknown user"</span></span></code></pre></div>
|
||
<h3 data-number="1.9.5" id="recursion"><span
|
||
class="header-section-number">1.9.5</span> Recursion</h3>
|
||
<p>In Haskell, all sorts of loops are implemented with recursion.
|
||
Function calls are very efficient, so you don’t need to worry about
|
||
performance. (We’ll talk about performance later).</p>
|
||
<p>Learning how to do simple things with recursion in Haskell will help
|
||
you use recursion on more complex problems later. Recursion is also
|
||
often a useful way for thinking about solving harder problems.</p>
|
||
<p>Here’s our first recursive function which computes the factorial. In
|
||
mathematics, factorial is the product of <em>n</em> first positive
|
||
integers and is written as <em>n!</em>. The definition of factorial
|
||
is</p>
|
||
<blockquote>
|
||
<p><em>n! = n * (n-1) * … * 1</em></p>
|
||
</blockquote>
|
||
<p>For example, <em>4! = 4*3*2*1 = 24</em>. Well anyway, here’s the
|
||
Haskell implementation of factorial:</p>
|
||
<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><span class="ot">factorial ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a>factorial <span class="dv">1</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a>factorial n <span class="ot">=</span> n <span class="op">*</span> factorial (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>This is how it works. We use <code>==></code> to mean “evaluates
|
||
to”.</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>factorial <span class="dv">3</span></span>
|
||
<span id="cb66-2"><a href="#cb66-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span> <span class="op">*</span> factorial (<span class="dv">3</span><span class="op">-</span><span class="dv">1</span>)</span>
|
||
<span id="cb66-3"><a href="#cb66-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span> <span class="op">*</span> factorial <span class="dv">2</span></span>
|
||
<span id="cb66-4"><a href="#cb66-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span> <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> factorial <span class="dv">1</span></span>
|
||
<span id="cb66-5"><a href="#cb66-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span> <span class="op">*</span> <span class="dv">2</span> <span class="op">*</span> <span class="dv">1</span></span>
|
||
<span id="cb66-6"><a href="#cb66-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">6</span></span></code></pre></div>
|
||
<p>What happens when you evaluate <code>factorial (-1)</code>?</p>
|
||
<p>Here’s another example:</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="co">-- compute the sum 1^2+2^2+3^2+...+n^2</span></span>
|
||
<span id="cb67-2"><a href="#cb67-2" aria-hidden="true" tabindex="-1"></a>squareSum <span class="dv">0</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb67-3"><a href="#cb67-3" aria-hidden="true" tabindex="-1"></a>squareSum n <span class="ot">=</span> n<span class="op">^</span><span class="dv">2</span> <span class="op">+</span> squareSum (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>A function can call itself recursively multiple times. As an example
|
||
let’s consider the <em>Fibonacci sequence</em> from mathematics. The
|
||
Fibonacci sequence is a sequence of integers with the following
|
||
definition.</p>
|
||
<blockquote>
|
||
<p>The sequence starts with 1, 1. To get the next element of the
|
||
sequence, sum the previous two elements of the sequence.</p>
|
||
</blockquote>
|
||
<p>The first elements of the Fibonacci sequence are 1, 1, 2, 3, 5, 8, 13
|
||
and so on. Here’s a function <code>fibonacci</code> which computes the
|
||
<code>n</code>th element in the Fibonacci sequence. Note how it mirrors
|
||
the mathematical definition.</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><span class="co">-- Fibonacci numbers, slow version</span></span>
|
||
<span id="cb68-2"><a href="#cb68-2" aria-hidden="true" tabindex="-1"></a>fibonacci <span class="dv">1</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb68-3"><a href="#cb68-3" aria-hidden="true" tabindex="-1"></a>fibonacci <span class="dv">2</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb68-4"><a href="#cb68-4" aria-hidden="true" tabindex="-1"></a>fibonacci n <span class="ot">=</span> fibonacci (n<span class="op">-</span><span class="dv">2</span>) <span class="op">+</span> fibonacci (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>Here’s how <code>fibonacci 5</code> evaluates:</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>fibonacci <span class="dv">5</span></span>
|
||
<span id="cb69-2"><a href="#cb69-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> fibonacci <span class="dv">3</span> <span class="op">+</span> fibonacci <span class="dv">4</span></span>
|
||
<span id="cb69-3"><a href="#cb69-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> (fibonacci <span class="dv">1</span> <span class="op">+</span> fibonacci <span class="dv">2</span>) <span class="op">+</span> fibonacci <span class="dv">4</span></span>
|
||
<span id="cb69-4"><a href="#cb69-4" 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> fibonacci <span class="dv">4</span></span>
|
||
<span id="cb69-5"><a href="#cb69-5" 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> (fibonacci <span class="dv">2</span> <span class="op">+</span> fibonacci <span class="dv">3</span>)</span>
|
||
<span id="cb69-6"><a href="#cb69-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="op">+</span> (fibonacci <span class="dv">2</span> <span class="op">+</span> (fibonacci <span class="dv">1</span> <span class="op">+</span> fibonacci <span class="dv">2</span>))</span>
|
||
<span id="cb69-7"><a href="#cb69-7" 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">1</span> <span class="op">+</span> ( <span class="dv">1</span> <span class="op">+</span> <span class="dv">1</span> ))</span>
|
||
<span id="cb69-8"><a href="#cb69-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">5</span></span></code></pre></div>
|
||
<p>Note how <code>fibonacci 3</code> gets evaluated twice and
|
||
<code>fibonacci 2</code> three times. This is not the most efficient
|
||
implementation of the <code>fibonacci</code> function. We’ll get back to
|
||
this in the next lecture. Another way to think about the evaluation of
|
||
the fibonacci function is to visualize it as a tree (we abbreviate
|
||
<code>fibonacci</code> as <code>fib</code>):
|
||
<!-- There could be some animation or a clickable interactive element for
|
||
cycling through these images: --></p>
|
||
<p><img src="img/Fibonacci-step1.svg" /></p>
|
||
<p><img src="img/Fibonacci-step2.svg" /></p>
|
||
<p><img src="img/Fibonacci-step3.svg" /></p>
|
||
<p><img src="img/Fibonacci-step4.svg" /></p>
|
||
<p><img src="img/Fibonacci-step5.svg" /></p>
|
||
<p><img src="img/Fibonacci-step6.svg" /></p>
|
||
<p><img src="img/Fibonacci-step7.svg" /></p>
|
||
<p><img src="img/Fibonacci-step8.svg" /></p>
|
||
<!--
|
||
```
|
||
_____ + _____
|
||
fib 5 ==> | |
|
||
fib 3 fib 4
|
||
|
||
|
||
==> __________ + __________
|
||
| |
|
||
_____ + _____ _____ + _____
|
||
| | | |
|
||
fib 1 fib 2 fib 2 fib 3
|
||
|
||
|
||
==> __________ + __________
|
||
| |
|
||
_____ + _____ _____ + _____
|
||
| | | |
|
||
1 1 1 ___ + ___
|
||
| |
|
||
fib 1 fib 2
|
||
|
||
|
||
==> __________ + __________
|
||
| |
|
||
_____ + _____ _____ + _____
|
||
| | | |
|
||
1 1 1 ___ + ___
|
||
| |
|
||
1 1
|
||
```
|
||
-->
|
||
<p>This tree then exaclty corresponds with the expression
|
||
<code>(1 + 1) + (1 + (1 + 1))</code>. Recursion can often produce
|
||
chain-like, tree-like, nested, or loopy structures and computations.
|
||
Recursion is one of the main techniques in functional programming, so
|
||
it’s worth spending some effort in learning it.</p>
|
||
<!--  -->
|
||
<h2 data-number="1.10" id="all-together-now"><span
|
||
class="header-section-number">1.10</span> All Together Now!</h2>
|
||
<p>Finally, here’s a complete Haskell module that uses ifs, pattern
|
||
matching, local defintions and recursion. The module is interested in
|
||
the <a
|
||
href="https://en.wikipedia.org/wiki/Collatz_conjecture"><em>Collatz
|
||
conjecture</em></a>, a famous open problem in mathematics. It asks:</p>
|
||
<blockquote>
|
||
<p>Does the Collatz sequence eventually reach 1 for all positive integer
|
||
initial values?</p>
|
||
</blockquote>
|
||
<p>The Collatz sequence is defined by taking any number as a starting
|
||
value, and then repeatedly performing the following operation:</p>
|
||
<ul>
|
||
<li>if the number is even, divide it by two</li>
|
||
<li>if the number is odd, triple it and add one</li>
|
||
</ul>
|
||
<p>As an example, the Collatz sequence for 3 is: 3, 10, 5, 16, 8, 4, 2,
|
||
1, 4, 2, 1, 4, 2, 1 … As you can see, once the number reaches 1, it gets
|
||
caught in a loop.</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="kw">module</span> <span class="dt">Collatz</span> <span class="kw">where</span></span>
|
||
<span id="cb70-2"><a href="#cb70-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb70-3"><a href="#cb70-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- one step of the Collatz sequence</span></span>
|
||
<span id="cb70-4"><a href="#cb70-4" aria-hidden="true" tabindex="-1"></a><span class="ot">step ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb70-5"><a href="#cb70-5" aria-hidden="true" tabindex="-1"></a>step x <span class="ot">=</span> <span class="kw">if</span> <span class="fu">even</span> x <span class="kw">then</span> down <span class="kw">else</span> up</span>
|
||
<span id="cb70-6"><a href="#cb70-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> down <span class="ot">=</span> <span class="fu">div</span> x <span class="dv">2</span></span>
|
||
<span id="cb70-7"><a href="#cb70-7" aria-hidden="true" tabindex="-1"></a> up <span class="ot">=</span> <span class="dv">3</span><span class="op">*</span>x<span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb70-8"><a href="#cb70-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb70-9"><a href="#cb70-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- collatz x computes how many steps it takes for the Collatz sequence</span></span>
|
||
<span id="cb70-10"><a href="#cb70-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- to reach 1 when starting from x</span></span>
|
||
<span id="cb70-11"><a href="#cb70-11" aria-hidden="true" tabindex="-1"></a><span class="ot">collatz ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb70-12"><a href="#cb70-12" aria-hidden="true" tabindex="-1"></a>collatz <span class="dv">1</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb70-13"><a href="#cb70-13" aria-hidden="true" tabindex="-1"></a>collatz x <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> collatz (step x)</span>
|
||
<span id="cb70-14"><a href="#cb70-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb70-15"><a href="#cb70-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- longest finds the number with the longest Collatz sequence for initial values</span></span>
|
||
<span id="cb70-16"><a href="#cb70-16" aria-hidden="true" tabindex="-1"></a><span class="co">-- between 0 and upperBound</span></span>
|
||
<span id="cb70-17"><a href="#cb70-17" aria-hidden="true" tabindex="-1"></a><span class="ot">longest ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb70-18"><a href="#cb70-18" aria-hidden="true" tabindex="-1"></a>longest upperBound <span class="ot">=</span> longest' <span class="dv">0</span> <span class="dv">0</span> upperBound</span>
|
||
<span id="cb70-19"><a href="#cb70-19" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb70-20"><a href="#cb70-20" aria-hidden="true" tabindex="-1"></a><span class="co">-- helper function for longest</span></span>
|
||
<span id="cb70-21"><a href="#cb70-21" aria-hidden="true" tabindex="-1"></a><span class="ot">longest' ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb70-22"><a href="#cb70-22" aria-hidden="true" tabindex="-1"></a><span class="co">-- end of recursion, return longest length found</span></span>
|
||
<span id="cb70-23"><a href="#cb70-23" aria-hidden="true" tabindex="-1"></a>longest' number _ <span class="dv">0</span> <span class="ot">=</span> number</span>
|
||
<span id="cb70-24"><a href="#cb70-24" aria-hidden="true" tabindex="-1"></a><span class="co">-- recursion step: check if n has a longer Collatz sequence than the current known longest</span></span>
|
||
<span id="cb70-25"><a href="#cb70-25" aria-hidden="true" tabindex="-1"></a>longest' number maxlength n <span class="ot">=</span></span>
|
||
<span id="cb70-26"><a href="#cb70-26" aria-hidden="true" tabindex="-1"></a> <span class="kw">if</span> len <span class="op">></span> maxlength</span>
|
||
<span id="cb70-27"><a href="#cb70-27" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> longest' n len (n<span class="op">-</span><span class="dv">1</span>)</span>
|
||
<span id="cb70-28"><a href="#cb70-28" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> longest' number maxlength (n<span class="op">-</span><span class="dv">1</span>)</span>
|
||
<span id="cb70-29"><a href="#cb70-29" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> len <span class="ot">=</span> collatz n</span></code></pre></div>
|
||
<p>We can load the program in GHCi and play with it.</p>
|
||
<pre><code>$ stack ghci
|
||
GHCi, version 9.2.8: https://www.haskell.org/ghc/ :? for help
|
||
Prelude> :load Collatz.hs
|
||
[1 of 1] Compiling Collatz ( Collatz.hs, interpreted )
|
||
Ok, one module loaded.
|
||
*Collatz></code></pre>
|
||
<p>Let’s verify that our program computes the start of the Collatz
|
||
sequence for 3 correctly.</p>
|
||
<pre><code>*Collatz> step 3
|
||
10
|
||
*Collatz> step 10
|
||
5
|
||
*Collatz> step 5
|
||
16</code></pre>
|
||
<p>How many steps does it take for 3 to reach 1?</p>
|
||
<pre><code>*Collatz> collatz 3
|
||
7</code></pre>
|
||
<p>What’s the longest Collatz sequence for a starting value under 10?
|
||
What about 100?</p>
|
||
<pre><code>*Collatz> longest 10
|
||
9
|
||
*Collatz> longest 100
|
||
97</code></pre>
|
||
<p>The lengths of these Collatz sequences are:</p>
|
||
<pre><code>*Collatz> collatz 9
|
||
19
|
||
*Collatz> collatz 97
|
||
118</code></pre>
|
||
<h2 data-number="1.11" id="a-word-about-indentation"><span
|
||
class="header-section-number">1.11</span> A Word About Indentation</h2>
|
||
<p>The previous examples have been fancily indented. In Haskell
|
||
indentation matters, a bit like in Python. The complete set of rules for
|
||
indentation is hard to describe, but you should get along fine with
|
||
these rules of thumb:</p>
|
||
<ol type="1">
|
||
<li>Things that are grouped together start from the same column</li>
|
||
<li>If an expression (or equation) has to be split on to many lines,
|
||
increase indentation</li>
|
||
</ol>
|
||
<p>While you can get away with using tabs, it is highly recommended to
|
||
use spaces for all indenting.</p>
|
||
<p>Some examples are in order.</p>
|
||
<p>These all are ok:</p>
|
||
<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>i x <span class="ot">=</span> <span class="kw">let</span> y <span class="ot">=</span> x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x <span class="kw">in</span> <span class="fu">div</span> y <span class="dv">5</span></span>
|
||
<span id="cb76-2"><a href="#cb76-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb76-3"><a href="#cb76-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- let and in are grouped together, an expression is split</span></span>
|
||
<span id="cb76-4"><a href="#cb76-4" aria-hidden="true" tabindex="-1"></a>j x <span class="ot">=</span> <span class="kw">let</span> y <span class="ot">=</span> x<span class="op">+</span>x<span class="op">+</span>x</span>
|
||
<span id="cb76-5"><a href="#cb76-5" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x</span>
|
||
<span id="cb76-6"><a href="#cb76-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">div</span> y <span class="dv">5</span></span>
|
||
<span id="cb76-7"><a href="#cb76-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb76-8"><a href="#cb76-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- the definitions of a and b are grouped together</span></span>
|
||
<span id="cb76-9"><a href="#cb76-9" aria-hidden="true" tabindex="-1"></a>k <span class="ot">=</span> a <span class="op">+</span> b</span>
|
||
<span id="cb76-10"><a href="#cb76-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> a <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb76-11"><a href="#cb76-11" aria-hidden="true" tabindex="-1"></a> b <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb76-12"><a href="#cb76-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb76-13"><a href="#cb76-13" aria-hidden="true" tabindex="-1"></a>l <span class="ot">=</span> a <span class="op">+</span> b</span>
|
||
<span id="cb76-14"><a href="#cb76-14" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span>
|
||
<span id="cb76-15"><a href="#cb76-15" aria-hidden="true" tabindex="-1"></a> a <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb76-16"><a href="#cb76-16" aria-hidden="true" tabindex="-1"></a> b <span class="ot">=</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>These are not ok:</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="co">-- indentation not increased even though expression split on many lines</span></span>
|
||
<span id="cb77-2"><a href="#cb77-2" aria-hidden="true" tabindex="-1"></a>i x <span class="ot">=</span> <span class="kw">let</span> y <span class="ot">=</span> x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x</span>
|
||
<span id="cb77-3"><a href="#cb77-3" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="fu">div</span> y <span class="dv">5</span></span>
|
||
<span id="cb77-4"><a href="#cb77-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb77-5"><a href="#cb77-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- indentation not increased even though expression is split</span></span>
|
||
<span id="cb77-6"><a href="#cb77-6" aria-hidden="true" tabindex="-1"></a>j x <span class="ot">=</span> <span class="kw">let</span> y <span class="ot">=</span> x<span class="op">+</span>x<span class="op">+</span>x</span>
|
||
<span id="cb77-7"><a href="#cb77-7" aria-hidden="true" tabindex="-1"></a> <span class="op">+</span>x<span class="op">+</span>x<span class="op">+</span>x</span>
|
||
<span id="cb77-8"><a href="#cb77-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">in</span> <span class="fu">div</span> y <span class="dv">5</span></span>
|
||
<span id="cb77-9"><a href="#cb77-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb77-10"><a href="#cb77-10" aria-hidden="true" tabindex="-1"></a><span class="co">-- grouped things are not aligned</span></span>
|
||
<span id="cb77-11"><a href="#cb77-11" aria-hidden="true" tabindex="-1"></a>k <span class="ot">=</span> a <span class="op">+</span> b</span>
|
||
<span id="cb77-12"><a href="#cb77-12" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> a <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb77-13"><a href="#cb77-13" aria-hidden="true" tabindex="-1"></a> b <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb77-14"><a href="#cb77-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb77-15"><a href="#cb77-15" aria-hidden="true" tabindex="-1"></a><span class="co">-- grouped things are not aligned</span></span>
|
||
<span id="cb77-16"><a href="#cb77-16" aria-hidden="true" tabindex="-1"></a>l <span class="ot">=</span> a <span class="op">+</span> b</span>
|
||
<span id="cb77-17"><a href="#cb77-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span></span>
|
||
<span id="cb77-18"><a href="#cb77-18" aria-hidden="true" tabindex="-1"></a> a <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb77-19"><a href="#cb77-19" aria-hidden="true" tabindex="-1"></a> b <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb77-20"><a href="#cb77-20" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb77-21"><a href="#cb77-21" aria-hidden="true" tabindex="-1"></a><span class="co">-- where is part of the equation, so indentation needs to increase</span></span>
|
||
<span id="cb77-22"><a href="#cb77-22" aria-hidden="true" tabindex="-1"></a>l <span class="ot">=</span> a <span class="op">+</span> b</span>
|
||
<span id="cb77-23"><a href="#cb77-23" aria-hidden="true" tabindex="-1"></a><span class="kw">where</span></span>
|
||
<span id="cb77-24"><a href="#cb77-24" aria-hidden="true" tabindex="-1"></a> a <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb77-25"><a href="#cb77-25" aria-hidden="true" tabindex="-1"></a> b <span class="ot">=</span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>If you make a mistake with the indentation, you’ll typically get a
|
||
parse error like this:</p>
|
||
<pre><code>Indent.hs:2:1: error: parse error on input ‘where’</code></pre>
|
||
<p>The error includes the line number, so just go over that line again.
|
||
If you can’t seem to get indentation to work, try putting everything on
|
||
just one long line at first.</p>
|
||
<h2 data-number="1.12" id="quiz"><span
|
||
class="header-section-number">1.12</span> Quiz</h2>
|
||
<p>At the end of each lecture you’ll find a quiz like this. The quizes
|
||
aren’t graded, they’re just here to help you check you’ve understood the
|
||
chapter. You can check your answer by clicking on an option. You’ll see
|
||
a green background if you were right, a red one if you were wrong. Feel
|
||
free to guess as many times as you want, just make sure you understand
|
||
why the right option is right in the end.</p>
|
||
<p>What is the Haskell equivalent of the C/Java/Python expression
|
||
<code>combine(prettify(lawn),construct(house,concrete))</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>combine prettify (lawn) construct (house concerete)</code>
|
||
</li>
|
||
<li>
|
||
<code>combine (prettify lawn (counstruct house concrete))</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>combine (prettify lawn) (construct house concrete)</code>
|
||
</li>
|
||
</ol>
|
||
What is the C/Java/Python equivalent of the Haskell expression
|
||
<code>send metric (double population + increase)</code>?
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>send(metric(double(population+increase)))</code>
|
||
</li>
|
||
<li>
|
||
<code>send(metric(double(population)+increase))</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>send(metric,double(population)+increase)</code>
|
||
</li>
|
||
<li>
|
||
<code>send(metric,double(population+increase))</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which one of the following claims is true in Haskell?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
Every value has a type
|
||
</li>
|
||
<li>
|
||
Every type has a value
|
||
</li>
|
||
<li>
|
||
Every statement has a type
|
||
</li>
|
||
</ol>
|
||
<p>Which one of the following claims is true in Haskell?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
It’s impossible to reuse the name of a variable
|
||
</li>
|
||
<li>
|
||
It’s possible to reassign a value to a variable
|
||
</li>
|
||
<li class="correct">
|
||
An <code>if</code> always requires both <code>then</code> and
|
||
<code>else</code>
|
||
</li>
|
||
</ol>
|
||
<p>What does the function
|
||
<code>f x = if even (x + 1) then x + 1 else f (x - 1)</code> do?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
Maps every value <code>x</code> to the least even number greater than or
|
||
equal to <code>x</code>
|
||
</li>
|
||
<li>
|
||
Maps every value <code>x</code> to the greatest even number less than or
|
||
equal to <code>x</code>
|
||
</li>
|
||
<li>
|
||
Maps every value to itself
|
||
</li>
|
||
</ol>
|
||
<p>Why is <code>3 * "F00"</code> not valid Haskell?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>3</code> and <code>"F00"</code> have different types
|
||
</li>
|
||
<li>
|
||
All numeric values need a decimal point
|
||
</li>
|
||
<li>
|
||
<code>"F00"</code> needs the prefix “0x”
|
||
</li>
|
||
</ol>
|
||
<p>Why does <code>7.0 `div` 2</code> give an error?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
Because <code>div</code> is not defined for the type <code>Double</code>
|
||
</li>
|
||
<li>
|
||
Because <code>div</code> is not defined for the type <code>Int</code>
|
||
</li>
|
||
<li>
|
||
Because <code>`...`</code> is used for delimiting strings.
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="1.13" id="working-on-the-exercises"><span
|
||
class="header-section-number">1.13</span> Working on the Exercises</h2>
|
||
<p>The course materials, including exercises, are available in a Git
|
||
repository on GitHub at <a href="https://github.com/moocfi/haskell-mooc"
|
||
class="uri">https://github.com/moocfi/haskell-mooc</a>. If you’re not
|
||
familiar with Git, see <a
|
||
href="https://help.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository">GitHub’s
|
||
instructions on cloning a repository</a>.</p>
|
||
<p>Once you’ve cloned the <code>haskell-mooc</code> repository, go into
|
||
the <code>exercises</code> directory. To download and build dependencies
|
||
needed for running the exercise tests (such as the correct version of
|
||
GHC and various libraries), run following command in your terminal:</p>
|
||
<div class="sourceCode" id="cb79"><pre
|
||
class="sourceCode sh"><code class="sourceCode bash"><span id="cb79-1"><a href="#cb79-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> stack build</span></code></pre></div>
|
||
<p>Do note that the dependencies are multiple gigabytes and it will take
|
||
a while for the command to finish.</p>
|
||
<p><strong>Note!</strong> Here are some fixes for common problems with
|
||
<code>stack build</code>:</p>
|
||
<ul>
|
||
<li>If you get an error like
|
||
<code>While building package zlib-0.6.2.3</code>, you need to install
|
||
the zlib library headers. The right command for Ubuntu is
|
||
<code>sudo apt install zlib1g-dev</code>.</li>
|
||
<li>If you get an error like <code>cannot find -ltinfo</code>, you need
|
||
to install the ncurses headers. The right command for Ubuntu is
|
||
<code>sudo apt install libncurses-dev</code>. The right command for
|
||
Fedora is <code>dnf install ncurses-devel</code>.</li>
|
||
<li>If you get an error like
|
||
<code>Downloading lts-18.18 build plan ... RedownloadInvalidResponse</code>,
|
||
your version of stack is too old. Run <code>stack upgrade</code> to get
|
||
a newer one.</li>
|
||
</ul>
|
||
<p>There are primarily two types of files in the <code>exercises</code>
|
||
directory: exercise sets named <code>SetNX.hs</code> and accompanying
|
||
test program for the exercises named <code>SetNXTest.hs</code>. Both are
|
||
Haskell source files, but only the exercise file should to be edited
|
||
when solving the exercises. Instructions to all individual exercises are
|
||
embedded in the exercise file as comments.</p>
|
||
<p>Use the tests file to check your answers. For example when you have
|
||
solved some of the exercises in <code>Set1.hs</code>, run the following
|
||
command:</p>
|
||
<div class="sourceCode" id="cb80"><pre
|
||
class="sourceCode sh"><code class="sourceCode bash"><span id="cb80-1"><a href="#cb80-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> stack runhaskell Set1Test.hs</span></code></pre></div>
|
||
<p>The output of the tests looks something like this:</p>
|
||
<pre><code>===== EXERCISE 1
|
||
+++++ Pass
|
||
===== EXERCISE 2
|
||
+++++ Pass
|
||
===== EXERCISE 3
|
||
*** Failed! Falsified (after 2 tests and 1 shrink):
|
||
quadruple 1
|
||
Expected: 4
|
||
Was: 2
|
||
|
||
----- Fail
|
||
===== EXERCISE 4
|
||
+++++ Pass
|
||
===== EXERCISE 5
|
||
+++++ Pass
|
||
===== EXERCISE 6
|
||
+++++ Pass
|
||
===== EXERCISE 7
|
||
+++++ Pass
|
||
===== EXERCISE 8
|
||
+++++ Pass
|
||
===== EXERCISE 9
|
||
+++++ Pass
|
||
===== EXERCISE 10
|
||
+++++ Pass
|
||
===== EXERCISE 11
|
||
+++++ Pass
|
||
===== EXERCISE 12
|
||
+++++ Pass
|
||
===== EXERCISE 13
|
||
+++++ Pass
|
||
===== EXERCISE 14
|
||
+++++ Pass
|
||
===== EXERCISE 15
|
||
+++++ Pass
|
||
===== EXERCISE 16
|
||
+++++ Pass
|
||
===== EXERCISE 17
|
||
+++++ Pass
|
||
===== EXERCISE 18
|
||
+++++ Pass
|
||
===== EXERCISE 19
|
||
+++++ Pass
|
||
===== TOTAL
|
||
1101111111111111111
|
||
18 / 19</code></pre>
|
||
<p>In the example above, I’ve made a mistake in exercise 3.</p>
|
||
<p>To make debugging faster and more straightforward, I can load my
|
||
exercise file in GHCi, which allows me to evaluate any top-level
|
||
function manually. For instance I can verify the above mistake by:</p>
|
||
<pre><code>$ stack ghci Set1.hs
|
||
GHCi, version 9.2.8: https://www.haskell.org/ghc/ :? for help
|
||
[1 of 2] Compiling Mooc.Todo ( Mooc/Todo.hs, interpreted )
|
||
[2 of 2] Compiling Set1 ( Set1.hs, interpreted )
|
||
Ok, two modules loaded.
|
||
*Set1> quadruple 1
|
||
2</code></pre>
|
||
<p>Once you’re done with an exercise set, you can turn it in on the <a
|
||
href="https://haskell.mooc.fi/submit.php">Submit page</a> on the course
|
||
pages. After that you can see the results of your submission on the <a
|
||
href="https://haskell.mooc.fi/results.php">Results page</a> and your
|
||
total score on the <a href="https://haskell.mooc.fi/status.php">My
|
||
status page</a>.</p>
|
||
<p><strong>Note!</strong> You may turn in an exercise set as many times
|
||
as you want.</p>
|
||
<p><strong>Note!</strong> If you don’t want to use Stack or can’t get it
|
||
working, you should also be able to run the tests with <a
|
||
href="https://www.haskell.org/cabal/download.html">Cabal</a> like
|
||
this:</p>
|
||
<div class="sourceCode" id="cb83"><pre
|
||
class="sourceCode sh"><code class="sourceCode bash"><span id="cb83-1"><a href="#cb83-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> cabal v2-build</span>
|
||
<span id="cb83-2"><a href="#cb83-2" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> cabal v2-exec runhaskell Set1Test.hs</span></code></pre></div>
|
||
<h3 data-number="1.13.1" id="model-solutions"><span
|
||
class="header-section-number">1.13.1</span> Model Solutions</h3>
|
||
<p>Once you’ve successfully completed all the exercises in a set, you
|
||
can view the model solutions on the <a
|
||
href="https://haskell.mooc.fi/status">My status page</a>. It’s useful to
|
||
glance at the model solutions, they might show you a technique you’ve
|
||
missed!</p>
|
||
<h2 data-number="1.14" id="exercises"><span
|
||
class="header-section-number">1.14</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set1.hs">Set1</a></li>
|
||
</ul>
|
||
<h1 data-number="2" id="lecture-2-either-you-die-a-hero"><span
|
||
class="header-section-number">2</span> Lecture 2: Either You Die a
|
||
Hero…</h1>
|
||
<ul>
|
||
<li>More about recursion</li>
|
||
<li>Guards</li>
|
||
<li>More types: lists, <code>Maybe</code>, <code>Either</code></li>
|
||
<li>Polymorphism</li>
|
||
</ul>
|
||
<h2 data-number="2.1" id="recursion-and-helper-functions"><span
|
||
class="header-section-number">2.1</span> Recursion and Helper
|
||
Functions</h2>
|
||
<p>Often you’ll find you need helper variables in recursion to keep
|
||
track of things. You can get them by defining a helper function with
|
||
more arguments. Analogy: arguments of the helper function are variables
|
||
you update in your loop.</p>
|
||
<p>Here’s an example of how you would convert a loop (in Java or Python)
|
||
into a recursive helper function in Haskell.</p>
|
||
<p>Java:</p>
|
||
<div class="sourceCode" id="cb84"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb84-1"><a href="#cb84-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="bu">String</span> <span class="fu">repeatString</span><span class="op">(</span><span class="dt">int</span> n<span class="op">,</span> <span class="bu">String</span> str<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb84-2"><a href="#cb84-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">String</span> result <span class="op">=</span> <span class="st">""</span><span class="op">;</span></span>
|
||
<span id="cb84-3"><a href="#cb84-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span>n<span class="op">></span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb84-4"><a href="#cb84-4" aria-hidden="true" tabindex="-1"></a> result <span class="op">=</span> result<span class="op">+</span>str<span class="op">;</span></span>
|
||
<span id="cb84-5"><a href="#cb84-5" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> n<span class="op">-</span><span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb84-6"><a href="#cb84-6" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb84-7"><a href="#cb84-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result<span class="op">;</span></span>
|
||
<span id="cb84-8"><a href="#cb84-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>Python:</p>
|
||
<div class="sourceCode" id="cb85"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span id="cb85-1"><a href="#cb85-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> repeatString(n, <span class="bu">str</span>):</span>
|
||
<span id="cb85-2"><a href="#cb85-2" aria-hidden="true" tabindex="-1"></a> result <span class="op">=</span> <span class="st">""</span></span>
|
||
<span id="cb85-3"><a href="#cb85-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> n<span class="op">></span><span class="dv">0</span>:</span>
|
||
<span id="cb85-4"><a href="#cb85-4" aria-hidden="true" tabindex="-1"></a> result <span class="op">=</span> result<span class="op">+</span><span class="bu">str</span></span>
|
||
<span id="cb85-5"><a href="#cb85-5" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> n<span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb85-6"><a href="#cb85-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> result</span></code></pre></div>
|
||
<p>Haskell:</p>
|
||
<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>repeatString n str <span class="ot">=</span> repeatHelper n str <span class="st">""</span></span>
|
||
<span id="cb86-2"><a href="#cb86-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb86-3"><a href="#cb86-3" aria-hidden="true" tabindex="-1"></a>repeatHelper n str result <span class="ot">=</span> <span class="kw">if</span> (n<span class="op">==</span><span class="dv">0</span>)</span>
|
||
<span id="cb86-4"><a href="#cb86-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> result</span>
|
||
<span id="cb86-5"><a href="#cb86-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> repeatHelper (n<span class="op">-</span><span class="dv">1</span>) str (result<span class="op">++</span>str)</span></code></pre></div>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> repeatString <span class="dv">3</span> <span class="st">"ABC"</span></span>
|
||
<span id="cb87-2"><a href="#cb87-2" aria-hidden="true" tabindex="-1"></a><span class="st">"ABCABCABC"</span></span></code></pre></div>
|
||
<p>You might have noticed that the Java and Python implementations look
|
||
a bit weird since they use while loops instead of for loops. This is
|
||
because this way the conversion to Haskell is more straightforward.</p>
|
||
<p>This can be made a bit tidier by using pattern matching instead of an
|
||
<code>if</code>:</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>repeatString n str <span class="ot">=</span> repeatHelper n str <span class="st">""</span></span>
|
||
<span id="cb88-2"><a href="#cb88-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb88-3"><a href="#cb88-3" aria-hidden="true" tabindex="-1"></a>repeatHelper <span class="dv">0</span> _ result <span class="ot">=</span> result</span>
|
||
<span id="cb88-4"><a href="#cb88-4" aria-hidden="true" tabindex="-1"></a>repeatHelper n str result <span class="ot">=</span> repeatHelper (n<span class="op">-</span><span class="dv">1</span>) str (result<span class="op">++</span>str)</span></code></pre></div>
|
||
<p>Here’s another example with more variables: computing fibonacci
|
||
numbers efficiently.</p>
|
||
<p>Java:</p>
|
||
<div class="sourceCode" id="cb89"><pre
|
||
class="sourceCode java"><code class="sourceCode java"><span id="cb89-1"><a href="#cb89-1" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span> <span class="dt">int</span> <span class="fu">fibonacci</span><span class="op">(</span><span class="dt">int</span> n<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb89-2"><a href="#cb89-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> a <span class="op">=</span> <span class="dv">0</span><span class="op">;</span></span>
|
||
<span id="cb89-3"><a href="#cb89-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> b <span class="op">=</span> <span class="dv">1</span><span class="op">;</span></span>
|
||
<span id="cb89-4"><a href="#cb89-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> <span class="op">(</span>n<span class="op">></span><span class="dv">1</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb89-5"><a href="#cb89-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">int</span> c <span class="op">=</span> a<span class="op">+</span>b<span class="op">;</span></span>
|
||
<span id="cb89-6"><a href="#cb89-6" aria-hidden="true" tabindex="-1"></a> a<span class="op">=</span>b<span class="op">;</span></span>
|
||
<span id="cb89-7"><a href="#cb89-7" aria-hidden="true" tabindex="-1"></a> b<span class="op">=</span>c<span class="op">;</span></span>
|
||
<span id="cb89-8"><a href="#cb89-8" aria-hidden="true" tabindex="-1"></a> n<span class="op">--;</span></span>
|
||
<span id="cb89-9"><a href="#cb89-9" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
|
||
<span id="cb89-10"><a href="#cb89-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> b<span class="op">;</span></span>
|
||
<span id="cb89-11"><a href="#cb89-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>Python:</p>
|
||
<div class="sourceCode" id="cb90"><pre
|
||
class="sourceCode python"><code class="sourceCode python"><span id="cb90-1"><a href="#cb90-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> fibonacci(n):</span>
|
||
<span id="cb90-2"><a href="#cb90-2" aria-hidden="true" tabindex="-1"></a> a <span class="op">=</span> <span class="dv">0</span></span>
|
||
<span id="cb90-3"><a href="#cb90-3" aria-hidden="true" tabindex="-1"></a> b <span class="op">=</span> <span class="dv">1</span></span>
|
||
<span id="cb90-4"><a href="#cb90-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">while</span> n<span class="op">></span><span class="dv">1</span>:</span>
|
||
<span id="cb90-5"><a href="#cb90-5" aria-hidden="true" tabindex="-1"></a> c <span class="op">=</span> a<span class="op">+</span>b</span>
|
||
<span id="cb90-6"><a href="#cb90-6" aria-hidden="true" tabindex="-1"></a> a <span class="op">=</span> b</span>
|
||
<span id="cb90-7"><a href="#cb90-7" aria-hidden="true" tabindex="-1"></a> b <span class="op">=</span> c</span>
|
||
<span id="cb90-8"><a href="#cb90-8" aria-hidden="true" tabindex="-1"></a> n <span class="op">=</span> n<span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb90-9"><a href="#cb90-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> b</span></code></pre></div>
|
||
<p>Haskell:</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="co">-- fibonacci numbers, fast version</span></span>
|
||
<span id="cb91-2"><a href="#cb91-2" aria-hidden="true" tabindex="-1"></a><span class="ot">fibonacci ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb91-3"><a href="#cb91-3" aria-hidden="true" tabindex="-1"></a>fibonacci n <span class="ot">=</span> fibonacci' <span class="dv">0</span> <span class="dv">1</span> n</span>
|
||
<span id="cb91-4"><a href="#cb91-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb91-5"><a href="#cb91-5" aria-hidden="true" tabindex="-1"></a><span class="ot">fibonacci' ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb91-6"><a href="#cb91-6" aria-hidden="true" tabindex="-1"></a>fibonacci' a b <span class="dv">1</span> <span class="ot">=</span> b</span>
|
||
<span id="cb91-7"><a href="#cb91-7" aria-hidden="true" tabindex="-1"></a>fibonacci' a b n <span class="ot">=</span> fibonacci' b (a<span class="op">+</span>b) (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>Take a while to study these and note how the Haskell recursion has
|
||
the same format as the loop.</p>
|
||
<p>Sidenote: Haskell programs often use the apostrophe to name helper
|
||
functions and alternative versions of functions. Thus the name
|
||
<code>fibonacci'</code> for the helper function above. Names like
|
||
<code>foo'</code> are usually read <em>foo prime</em> (like in
|
||
mathematics).</p>
|
||
<p>I said earlier that this version of fibonacci is more efficient. Can
|
||
you see why? The answer is that there are less recursive calls. The
|
||
expression <code>fibonacci' _ _ n</code> calls
|
||
<code>fibonacci' _ _ (n-1)</code> once, and this means that we can
|
||
compute <code>fibonacci' _ _ n</code> in <code>n</code> steps.</p>
|
||
<p>This type of recursion where a function just directly calls itself
|
||
with different arguments is called <em>tail recursion</em>. As you’ve
|
||
seen above, tail recursion corresponds to loops. This is why tail
|
||
recursion is often fast: the compiler can generate a loop in machine
|
||
code when it sees tail recursion.</p>
|
||
<h2 data-number="2.2" id="guards"><span
|
||
class="header-section-number">2.2</span> Guards</h2>
|
||
<p>Before we move on to new types, let’s go over one more piece of
|
||
Haskell syntax.</p>
|
||
<p>The <code>if then else</code> is often a bit cumbersome, especially
|
||
when you have multiple cases. An easier alternative is Haskell’s
|
||
<em>conditional definition</em> or <em>guarded definition</em>. This is
|
||
a bit like pattern matching in that you have multiple equations, but you
|
||
can have arbitrary code deciding which equation to use. Guarded
|
||
definitions look like this:</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>f x y z</span>
|
||
<span id="cb92-2"><a href="#cb92-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> condition1 <span class="ot">=</span> something</span>
|
||
<span id="cb92-3"><a href="#cb92-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> condition2 <span class="ot">=</span> other</span>
|
||
<span id="cb92-4"><a href="#cb92-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> somethingother</span></code></pre></div>
|
||
<p>A condition can be any expression of type <code>Bool</code>. The
|
||
first condition that evaluates to <code>True</code> is chosen. The word
|
||
<code>otherwise</code> is just an alias for <code>True</code>. It is
|
||
used to mark the default case.</p>
|
||
<h3 data-number="2.2.1" id="examples-1"><span
|
||
class="header-section-number">2.2.1</span> Examples</h3>
|
||
<p>Here are some examples of using guards. First off, we have a function
|
||
that describes the given number. Note how it is important to have the
|
||
<code>"Two"</code> case before the <code>"Even"</code> case.</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">describe ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb93-2"><a href="#cb93-2" aria-hidden="true" tabindex="-1"></a>describe n</span>
|
||
<span id="cb93-3"><a href="#cb93-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n<span class="op">==</span><span class="dv">2</span> <span class="ot">=</span> <span class="st">"Two"</span></span>
|
||
<span id="cb93-4"><a href="#cb93-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">even</span> n <span class="ot">=</span> <span class="st">"Even"</span></span>
|
||
<span id="cb93-5"><a href="#cb93-5" 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="st">"Three"</span></span>
|
||
<span id="cb93-6"><a href="#cb93-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n<span class="op">></span><span class="dv">100</span> <span class="ot">=</span> <span class="st">"Big!!"</span></span>
|
||
<span id="cb93-7"><a href="#cb93-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="st">"The number "</span><span class="op">++</span><span class="fu">show</span> n</span></code></pre></div>
|
||
<p>Here is factorial, implemented with guards instead of pattern
|
||
matching. Unlike the pattern-matching version, this one doesn’t loop
|
||
forever with negative inputs.</p>
|
||
<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>factorial n</span>
|
||
<span id="cb94-2"><a href="#cb94-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n<span class="op"><</span><span class="dv">0</span> <span class="ot">=</span> <span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb94-3"><a href="#cb94-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n<span class="op">==</span><span class="dv">0</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb94-4"><a href="#cb94-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> n <span class="op">*</span> factorial (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>You can even combine guards with pattern matching. Here’s the
|
||
implementation of a simple age guessing game:</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="ot">guessAge ::</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>
|
||
<span id="cb95-2"><a href="#cb95-2" aria-hidden="true" tabindex="-1"></a>guessAge <span class="st">"Griselda"</span> age</span>
|
||
<span id="cb95-3"><a href="#cb95-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> age <span class="op"><</span> <span class="dv">47</span> <span class="ot">=</span> <span class="st">"Too low!"</span></span>
|
||
<span id="cb95-4"><a href="#cb95-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> age <span class="op">></span> <span class="dv">47</span> <span class="ot">=</span> <span class="st">"Too high!"</span></span>
|
||
<span id="cb95-5"><a href="#cb95-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="st">"Correct!"</span></span>
|
||
<span id="cb95-6"><a href="#cb95-6" aria-hidden="true" tabindex="-1"></a>guessAge <span class="st">"Hansel"</span> age</span>
|
||
<span id="cb95-7"><a href="#cb95-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> age <span class="op"><</span> <span class="dv">12</span> <span class="ot">=</span> <span class="st">"Too low!"</span></span>
|
||
<span id="cb95-8"><a href="#cb95-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> age <span class="op">></span> <span class="dv">12</span> <span class="ot">=</span> <span class="st">"Too high!"</span></span>
|
||
<span id="cb95-9"><a href="#cb95-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="st">"Correct!"</span></span>
|
||
<span id="cb95-10"><a href="#cb95-10" aria-hidden="true" tabindex="-1"></a>guessAge name age <span class="ot">=</span> <span class="st">"Wrong name!"</span></span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> guessAge <span class="st">"Griselda"</span> <span class="dv">30</span></span>
|
||
<span id="cb96-2"><a href="#cb96-2" aria-hidden="true" tabindex="-1"></a><span class="st">"Too low!"</span></span>
|
||
<span id="cb96-3"><a href="#cb96-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> guessAge <span class="st">"Griselda"</span> <span class="dv">60</span></span>
|
||
<span id="cb96-4"><a href="#cb96-4" aria-hidden="true" tabindex="-1"></a><span class="st">"Too high!"</span></span>
|
||
<span id="cb96-5"><a href="#cb96-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> guessAge <span class="st">"Griselda"</span> <span class="dv">47</span></span>
|
||
<span id="cb96-6"><a href="#cb96-6" aria-hidden="true" tabindex="-1"></a><span class="st">"Correct!"</span></span>
|
||
<span id="cb96-7"><a href="#cb96-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> guessAge <span class="st">"Bob"</span> <span class="dv">30</span></span>
|
||
<span id="cb96-8"><a href="#cb96-8" aria-hidden="true" tabindex="-1"></a><span class="st">"Wrong name!"</span></span>
|
||
<span id="cb96-9"><a href="#cb96-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> guessAge <span class="st">"Hansel"</span> <span class="dv">10</span></span>
|
||
<span id="cb96-10"><a href="#cb96-10" aria-hidden="true" tabindex="-1"></a><span class="st">"Too low!"</span></span></code></pre></div>
|
||
<h2 data-number="2.3" id="lists"><span
|
||
class="header-section-number">2.3</span> Lists</h2>
|
||
<p>So far we’ve always worked with single values like number or
|
||
booleans. Strings contain multiple characters, but still in some sense a
|
||
string is just one piece of information. In order to be able to do
|
||
actual programming, we need to handle variable numbers of items. For
|
||
this we need <em>data structures</em>.</p>
|
||
<p>The basic datastructure in Haskell is the list. Lists are used to
|
||
store multiple values of the same type (in other words, Haskell lists
|
||
are homogeneous). This is what a list literal looks like:</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>[<span class="dv">0</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">1</span><span class="op">+</span><span class="dv">1</span>]</span></code></pre></div>
|
||
<p>A list type is written as <code>[Element]</code>, where
|
||
<code>Element</code> is the type of the lists elements. Here are some
|
||
more list expressions and their types:</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="dt">True</span>,<span class="dt">True</span>,<span class="dt">False</span>]<span class="ot"> ::</span> [<span class="dt">Bool</span>]</span>
|
||
<span id="cb98-2"><a href="#cb98-2" aria-hidden="true" tabindex="-1"></a>[<span class="st">"Moi"</span>,<span class="st">"Hei"</span>]<span class="ot"> ::</span> [<span class="dt">String</span>]</span>
|
||
<span id="cb98-3"><a href="#cb98-3" aria-hidden="true" tabindex="-1"></a>[]<span class="ot"> ::</span> [a] <span class="co">-- more about this later</span></span>
|
||
<span id="cb98-4"><a href="#cb98-4" aria-hidden="true" tabindex="-1"></a>[[<span class="dv">1</span>,<span class="dv">2</span>],[<span class="dv">3</span>,<span class="dv">4</span>]]<span class="ot"> ::</span> [[<span class="dt">Int</span>]] <span class="co">-- a list of lists</span></span>
|
||
<span id="cb98-5"><a href="#cb98-5" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span><span class="op">..</span><span class="dv">7</span>]<span class="ot"> ::</span> [<span class="dt">Int</span>] <span class="co">-- range syntax, value [1,2,3,4,5,6,7]</span></span></code></pre></div>
|
||
<p>Haskell lists are implemented as singly-linked lists. We’ll return to
|
||
this later.</p>
|
||
<h3 data-number="2.3.1" id="list-operations"><span
|
||
class="header-section-number">2.3.1</span> List Operations</h3>
|
||
<p>The Haskell standard library comes with lots of functions that
|
||
operate on lists. Here are some of the most important ones, together
|
||
with their types. We’ll get back to what <code>[a]</code> actually means
|
||
in a second, but for now you can imagine it means “any list”.</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="fu">head</span><span class="ot"> ::</span> [a] <span class="ot">-></span> a <span class="co">-- returns the first element</span></span>
|
||
<span id="cb99-2"><a href="#cb99-2" aria-hidden="true" tabindex="-1"></a><span class="fu">last</span><span class="ot"> ::</span> [a] <span class="ot">-></span> a <span class="co">-- returns the last element</span></span>
|
||
<span id="cb99-3"><a href="#cb99-3" aria-hidden="true" tabindex="-1"></a><span class="fu">tail</span><span class="ot"> ::</span> [a] <span class="ot">-></span> [a] <span class="co">-- returns everything except the first element</span></span>
|
||
<span id="cb99-4"><a href="#cb99-4" aria-hidden="true" tabindex="-1"></a><span class="fu">init</span><span class="ot"> ::</span> [a] <span class="ot">-></span> [a] <span class="co">-- returns everything except the last element</span></span>
|
||
<span id="cb99-5"><a href="#cb99-5" aria-hidden="true" tabindex="-1"></a><span class="fu">take</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> [a] <span class="co">-- returns the n first elements</span></span>
|
||
<span id="cb99-6"><a href="#cb99-6" 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 class="co">-- returns everything except the n first elements</span></span>
|
||
<span id="cb99-7"><a href="#cb99-7" aria-hidden="true" tabindex="-1"></a><span class="ot">(++) ::</span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> [a] <span class="co">-- lists are catenated with the ++ operator</span></span>
|
||
<span id="cb99-8"><a href="#cb99-8" aria-hidden="true" tabindex="-1"></a><span class="ot">(!!) ::</span> [a] <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> a <span class="co">-- lists are indexed with the !! operator</span></span>
|
||
<span id="cb99-9"><a href="#cb99-9" aria-hidden="true" tabindex="-1"></a><span class="fu">reverse</span><span class="ot"> ::</span> [a] <span class="ot">-></span> [a] <span class="co">-- reverse a list</span></span>
|
||
<span id="cb99-10"><a href="#cb99-10" aria-hidden="true" tabindex="-1"></a><span class="fu">null</span><span class="ot"> ::</span> [a] <span class="ot">-></span> <span class="dt">Bool</span> <span class="co">-- is this list empty?</span></span>
|
||
<span id="cb99-11"><a href="#cb99-11" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span><span class="ot"> ::</span> [a] <span class="ot">-></span> <span class="dt">Int</span> <span class="co">-- the length of a list</span></span></code></pre></div>
|
||
<p>Sidenote: the last two operations (<code>null</code> and
|
||
<code>length</code>) actually have more generic types, but here I’m
|
||
pretending that you can only use them on lists.</p>
|
||
<p>Lists can be compared with the familiar <code>==</code> operator.</p>
|
||
<p>Do you remember this from our first GHCi session?</p>
|
||
<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="op">></span> <span class="op">:</span>t <span class="st">"asdf"</span></span>
|
||
<span id="cb100-2"><a href="#cb100-2" aria-hidden="true" tabindex="-1"></a><span class="st">"asdf"</span><span class="ot"> ::</span> [<span class="dt">Char</span>]</span></code></pre></div>
|
||
<p>This means that <code>String</code> is just an alias for
|
||
<code>[Char]</code>, which means string is a list of characters. This
|
||
means you can use all list operations on strings!</p>
|
||
<p>Some list operations come from the module <code>Data.List</code>. You
|
||
can import a module in code or in GHCi with the
|
||
<code>import Data.List</code> syntax. One example is the
|
||
<code>sort</code> function which sorts a list:</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="kw">import</span> <span class="dt">Data.List</span></span>
|
||
<span id="cb101-2"><a href="#cb101-2" 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">0</span>,<span class="dv">5</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb101-3"><a href="#cb101-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">5</span>]</span></code></pre></div>
|
||
<p>Note how the set of imported modules shows up in the GHCi prompt.</p>
|
||
<h3 data-number="2.3.2" id="examples-2"><span
|
||
class="header-section-number">2.3.2</span> Examples</h3>
|
||
<p>Here are some examples of working with lists. In this case, instead
|
||
of showing you output from GHCi, I merely use <code>==></code> to
|
||
show what an expression evaluates to.</p>
|
||
<p>Indexing a list:</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>[<span class="dv">7</span>,<span class="dv">10</span>,<span class="dv">4</span>,<span class="dv">5</span>] <span class="op">!!</span> <span class="dv">2</span></span>
|
||
<span id="cb102-2"><a href="#cb102-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">4</span></span></code></pre></div>
|
||
<p>Defining a function that discards the 3rd and 4th elements of a list
|
||
using <code>take</code> and <code>drop</code>:</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>f xs <span class="ot">=</span> <span class="fu">take</span> <span class="dv">2</span> xs <span class="op">++</span> <span class="fu">drop</span> <span class="dv">4</span> xs</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>f [<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="dv">1</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="dv">6</span>]</span>
|
||
<span id="cb104-2"><a href="#cb104-2" aria-hidden="true" tabindex="-1"></a>f [<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></code></pre></div>
|
||
<p>Rotating a list by taking the first element and moving it to the
|
||
end:</p>
|
||
<div class="sourceCode" id="cb105"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb105-1"><a href="#cb105-1" aria-hidden="true" tabindex="-1"></a>g xs <span class="ot">=</span> <span class="fu">tail</span> xs <span class="op">++</span> [<span class="fu">head</span> xs]</span></code></pre></div>
|
||
<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>g [<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">1</span>]</span>
|
||
<span id="cb106-2"><a href="#cb106-2" aria-hidden="true" tabindex="-1"></a>g (g [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]) <span class="op">==></span> [<span class="dv">3</span>,<span class="dv">1</span>,<span class="dv">2</span>]</span></code></pre></div>
|
||
<p>Here’s an example of the range syntax:</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="fu">reverse</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">4</span>] <span class="op">==></span> [<span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">2</span>,<span class="dv">1</span>]</span></code></pre></div>
|
||
<h2 data-number="2.4" id="a-word-about-immutability-1"><span
|
||
class="header-section-number">2.4</span> A Word About Immutability</h2>
|
||
<p>Because Haskell is pure, it also means that functions can’t
|
||
<em>mutate</em> (change) their inputs. Mutation is a side effect, and
|
||
Haskell functions are only allowed output via their return value. This
|
||
means that Haskell list functions always return a new list. In
|
||
practice:</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="op">></span> list <span class="ot">=</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb108-2"><a href="#cb108-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">reverse</span> list</span>
|
||
<span id="cb108-3"><a href="#cb108-3" aria-hidden="true" tabindex="-1"></a>[<span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">2</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb108-4"><a href="#cb108-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> list</span>
|
||
<span id="cb108-5"><a href="#cb108-5" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb108-6"><a href="#cb108-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">drop</span> <span class="dv">2</span> list</span>
|
||
<span id="cb108-7"><a href="#cb108-7" aria-hidden="true" tabindex="-1"></a>[<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb108-8"><a href="#cb108-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> list</span>
|
||
<span id="cb108-9"><a href="#cb108-9" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span></code></pre></div>
|
||
<p>This might seem very inefficient but it turns out it can be both
|
||
performant and quite useful. We’ll get back to how Haskell
|
||
datastructures work in a later lecture.</p>
|
||
<h2 data-number="2.5"
|
||
id="a-word-about-type-inference-and-polymorphism"><span
|
||
class="header-section-number">2.5</span> A Word About Type Inference and
|
||
Polymorphism</h2>
|
||
<p>So what does a type like <code>head :: [a] -> a</code> mean? It
|
||
means given a list that contains elements of any type <code>a</code>,
|
||
the return value will be of the same type <code>a</code>.</p>
|
||
<p>In this type, <code>a</code> is a <em>type variable</em>. Type
|
||
variables are types that start with a small letter, e.g. <code>a</code>,
|
||
<code>b</code>, <code>thisIsATypeVariable</code>. A type variable means
|
||
a type that is not yet known, or in other words a type that could be
|
||
anything. Type variables can turn into <em>concrete types</em>
|
||
(e.g. <code>Bool</code>) by the process of <em>type inference</em> (also
|
||
called <em>unification</em>).</p>
|
||
<p>Let’s have a look at some examples. If we apply <code>head</code> to
|
||
a list of booleans, type inference will compare the type of head’s
|
||
argument, <code>[a]</code>, with the type of the actual argument,
|
||
<code>[Bool]</code> and deduce that <code>a</code> must be
|
||
<code>Bool</code>. This means that the return type of <code>head</code>
|
||
will in this case also be <code>Bool</code>.</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="fu">head</span><span class="ot"> ::</span> [a] <span class="ot">-></span> a</span>
|
||
<span id="cb109-2"><a href="#cb109-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> [<span class="dt">True</span>,<span class="dt">False</span>]<span class="ot"> ::</span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<p>The function <code>tail</code> takes a list, and returns a list of
|
||
the same type. If we apply <code>tail</code> to a list of booleans, the
|
||
return value will also be a list of booleans.</p>
|
||
<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><span class="fu">tail</span><span class="ot"> ::</span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb110-2"><a href="#cb110-2" aria-hidden="true" tabindex="-1"></a><span class="fu">tail</span> [<span class="dt">True</span>,<span class="dt">False</span>]<span class="ot"> ::</span> [<span class="dt">Bool</span>]</span></code></pre></div>
|
||
<p>If types don’t match, we get a type error. Consider the operator
|
||
<code>++</code> which takes two lists of the same type, as we can see
|
||
from its type <code>[a] -> [a] -> [a]</code>. If we try to apply
|
||
<code>++</code> to a list of booleans and a list of characters we get an
|
||
error. This is what happens in GHCi:</p>
|
||
<pre><code>Prelude> [True,False] ++ "Moi"
|
||
|
||
<interactive>:1:16:
|
||
Couldn't match expected type `Bool' against inferred type `Char'
|
||
Expected type: [Bool]
|
||
Inferred type: [Char]
|
||
In the second argument of `(++)', namely `"Moi"'
|
||
In the expression: [True, False] ++ "Moi"</code></pre>
|
||
<p>Type inference is really powerful. It uses the simple process of
|
||
unification to get us types for practically any Haskell expression.
|
||
Consider these two functions:</p>
|
||
<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>f xs ys <span class="ot">=</span> [<span class="fu">head</span> xs, <span class="fu">head</span> ys]</span>
|
||
<span id="cb112-2"><a href="#cb112-2" aria-hidden="true" tabindex="-1"></a>g zs <span class="ot">=</span> f <span class="st">"Moi"</span> zs</span></code></pre></div>
|
||
<p>We can ask GHCi for their types, and we will see that type inference
|
||
has figured out that the two arguments to <code>f</code> must have the
|
||
same type, since their heads get put into the same list.</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="op">></span> <span class="op">:</span>t f</span>
|
||
<span id="cb113-2"><a href="#cb113-2" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> [a] <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span></code></pre></div>
|
||
<p>The function <code>g</code>, which fixed one of the arguments of
|
||
<code>f</code> to a string (i.e. <code>[Char]</code>) gets a narrower
|
||
type. Type inference has decided that the argument <code>zs</code> to
|
||
<code>g</code> must also have type <code>[Char]</code>, since otherwise
|
||
the type of <code>f</code> would not match the call to
|
||
<code>f</code>.</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t g</span>
|
||
<span id="cb114-2"><a href="#cb114-2" aria-hidden="true" tabindex="-1"></a><span class="ot">g ::</span> [<span class="dt">Char</span>] <span class="ot">-></span> [<span class="dt">Char</span>]</span></code></pre></div>
|
||
<h3 data-number="2.5.1" id="sidenote-some-terminology"><span
|
||
class="header-section-number">2.5.1</span> Sidenote: Some
|
||
Terminology</h3>
|
||
<p>In a type like <code>[Char]</code> we call <code>Char</code> a
|
||
<em>type parameter</em>. A type like the list type that needs a type
|
||
parameter is called a <em>parameterized type</em>.</p>
|
||
<p>The fact that a function like <code>head</code> can be used with many
|
||
different types of arguments is called <em>polymorphism</em>. The
|
||
<code>head</code> function is said to be <em>polymorphic</em>. There are
|
||
many forms of polymorphism, and this Haskell form that uses type
|
||
variables is called <em>parametric polymorphism</em>.</p>
|
||
<h3 data-number="2.5.2" id="sidenote-type-annotations"><span
|
||
class="header-section-number">2.5.2</span> Sidenote: Type
|
||
Annotations</h3>
|
||
<p>Since Haskell has type inference, you don’t need to give any type
|
||
annotations. However even though type annotations aren’t required, there
|
||
are multiple reasons to add them:</p>
|
||
<ol type="1">
|
||
<li>They act as documentation</li>
|
||
<li>They act as assertions that the compiler checks: help you spot
|
||
mistakes</li>
|
||
<li>You can use type annotations to give a function a narrower type than
|
||
Haskell infers</li>
|
||
</ol>
|
||
<p>A good rule of thumb is to give top-level definitions type
|
||
annotations.</p>
|
||
<h2 data-number="2.6" id="the-maybe-type"><span
|
||
class="header-section-number">2.6</span> The <code>Maybe</code>
|
||
Type</h2>
|
||
<p>In addition to the list type, Haskell has other parameterized types
|
||
too. Let’s look at a very common and useful one: the <code>Maybe</code>
|
||
type.</p>
|
||
<p>Sometimes an operation doesn’t have a valid return value (E.g.
|
||
division by zero.). We have a couple of options in this situation. We
|
||
can use an error value, like <code>-1</code>. This is a bit ugly, not
|
||
always possible. We can throw an exception. This is impure. In some
|
||
other languages we would return a special null value that exists in
|
||
(almost) all types. However Haskell does not have a null.</p>
|
||
<p>The solution Haskell offers us instead is to change our return type
|
||
to a <code>Maybe</code> type. This is pure, safe and neat. The type
|
||
<code>Maybe a</code> has two <em>constructors</em>: <code>Nothing</code>
|
||
and <code>Just</code>. <code>Nothing</code> is just a constant, but
|
||
<code>Just</code> takes a parameter. More concretely:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Values</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Maybe Bool</code></td>
|
||
<td style="text-align: left;"><code>Nothing</code>,
|
||
<code>Just False</code>, <code>Just True</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Maybe Int</code></td>
|
||
<td style="text-align: left;"><code>Nothing</code>, <code>Just 0</code>,
|
||
<code>Just 1</code>, …</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Maybe [Int]</code></td>
|
||
<td style="text-align: left;"><code>Nothing</code>,
|
||
<code>Just []</code>, <code>Just [1,1337]</code>, …</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>You can think of <code>Maybe a</code> as being a bit like
|
||
<code>[a]</code> except there can only be 0 or 1 elements, not more.
|
||
Alternatively, you can think of <code>Maybe a</code> introducing a null
|
||
value to the type <code>a</code>. If you’re familiar with Java,
|
||
<code>Maybe Integer</code> is the Haskell equivalent of Java’s
|
||
<code>Optional<Integer></code>.</p>
|
||
<p>You can create <code>Maybe</code> values by either specifying
|
||
<code>Nothing</code> or <code>Just someOtherValue</code>:</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><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Nothing</span></span>
|
||
<span id="cb115-2"><a href="#cb115-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span><span class="ot"> ::</span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb115-3"><a href="#cb115-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Just</span> <span class="st">"a camel"</span></span>
|
||
<span id="cb115-4"><a href="#cb115-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"a camel"</span></span>
|
||
<span id="cb115-5"><a href="#cb115-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Just</span> <span class="st">"a camel"</span></span>
|
||
<span id="cb115-6"><a href="#cb115-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="st">"a camel"</span><span class="ot"> ::</span> <span class="dt">Maybe</span> [<span class="dt">Char</span>] <span class="co">-- the same as Maybe String</span></span>
|
||
<span id="cb115-7"><a href="#cb115-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Just</span> <span class="dt">True</span></span>
|
||
<span id="cb115-8"><a href="#cb115-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dt">True</span></span>
|
||
<span id="cb115-9"><a href="#cb115-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Just</span> <span class="dt">True</span></span>
|
||
<span id="cb115-10"><a href="#cb115-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dt">True</span><span class="ot"> ::</span> <span class="dt">Maybe</span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<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><span class="co">-- given a password, return (Just username) if login succeeds, Nothing otherwise</span></span>
|
||
<span id="cb116-2"><a href="#cb116-2" 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="cb116-3"><a href="#cb116-3" 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="cb116-4"><a href="#cb116-4" 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="cb116-5"><a href="#cb116-5" aria-hidden="true" tabindex="-1"></a>login _ <span class="ot">=</span> <span class="dt">Nothing</span></span></code></pre></div>
|
||
<p>You use a <code>Maybe</code> value by pattern matching on it. Usually
|
||
you define patterns for the <code>Nothing</code> and
|
||
<code>Just something</code> cases. Some examples:</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><span class="co">-- Multiply an Int with a Maybe Int. Nothing is treated as no multiplication at all.</span></span>
|
||
<span id="cb117-2"><a href="#cb117-2" aria-hidden="true" tabindex="-1"></a><span class="ot">perhapsMultiply ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb117-3"><a href="#cb117-3" aria-hidden="true" tabindex="-1"></a>perhapsMultiply i <span class="dt">Nothing</span> <span class="ot">=</span> i</span>
|
||
<span id="cb117-4"><a href="#cb117-4" aria-hidden="true" tabindex="-1"></a>perhapsMultiply i (<span class="dt">Just</span> j) <span class="ot">=</span> i<span class="op">*</span>j <span class="co">-- Note how j denotes the value inside the Just</span></span></code></pre></div>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> perhapsMultiply <span class="dv">3</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb118-2"><a href="#cb118-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb118-3"><a href="#cb118-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> perhapsMultiply <span class="dv">3</span> (<span class="dt">Just</span> <span class="dv">2</span>)</span>
|
||
<span id="cb118-4"><a href="#cb118-4" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></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="ot">intOrZero ::</span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb119-2"><a href="#cb119-2" aria-hidden="true" tabindex="-1"></a>intOrZero <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb119-3"><a href="#cb119-3" aria-hidden="true" tabindex="-1"></a>intOrZero (<span class="dt">Just</span> i) <span class="ot">=</span> i</span>
|
||
<span id="cb119-4"><a href="#cb119-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb119-5"><a href="#cb119-5" 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="cb119-6"><a href="#cb119-6" aria-hidden="true" tabindex="-1"></a>safeHead xs <span class="ot">=</span> <span class="kw">if</span> <span class="fu">null</span> xs <span class="kw">then</span> <span class="dt">Nothing</span> <span class="kw">else</span> <span class="dt">Just</span> (<span class="fu">head</span> xs)</span>
|
||
<span id="cb119-7"><a href="#cb119-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb119-8"><a href="#cb119-8" aria-hidden="true" tabindex="-1"></a><span class="ot">headOrZero ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb119-9"><a href="#cb119-9" aria-hidden="true" tabindex="-1"></a>headOrZero xs <span class="ot">=</span> intOrZero (safeHead xs)</span></code></pre></div>
|
||
<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>headOrZero [] <span class="op">==></span> intOrZero (safeHead []) <span class="op">==></span> intOrZero <span class="dt">Nothing</span> <span class="op">==></span> <span class="dv">0</span></span>
|
||
<span id="cb120-2"><a href="#cb120-2" aria-hidden="true" tabindex="-1"></a>headOrZero [<span class="dv">1</span>] <span class="op">==></span> intOrZero (safeHead [<span class="dv">1</span>]) <span class="op">==></span> intOrZero (<span class="dt">Just</span> <span class="dv">1</span>) <span class="op">==></span> <span class="dv">1</span></span></code></pre></div>
|
||
<h2 data-number="2.7" id="sidenote-constructors"><span
|
||
class="header-section-number">2.7</span> Sidenote: Constructors</h2>
|
||
<p>As you can see above, we can pattern match on the constructors of
|
||
<code>Maybe</code>: <code>Just</code> and <code>Nothing</code>. We’ll
|
||
get back to what constructors mean later. For now it’s enough to note
|
||
that constructors are special values that start with a capital letter
|
||
that you can pattern match on.</p>
|
||
<p>Other constructors that we’ve already seen include the constructors
|
||
of <code>Bool</code> – <code>True</code> and <code>False</code>. We’ll
|
||
introduce the constructors of the list type on the next lecture.</p>
|
||
<p>Constructors can be used just like Haskell values. Constructors that
|
||
take no arguments like <code>Nothing</code>, and <code>False</code> are
|
||
just constants. Constructors like <code>Just</code> that take an
|
||
argument behave like functions. They even have function types!</p>
|
||
<pre><code>Prelude> :t Just
|
||
Just :: a -> Maybe a</code></pre>
|
||
<h2 data-number="2.8" id="the-either-type"><span
|
||
class="header-section-number">2.8</span> The <code>Either</code>
|
||
type</h2>
|
||
<p>Sometimes it would be nice if you could add an error message or
|
||
something to <code>Nothing</code>. That’s why we have the
|
||
<code>Either</code> type. The <code>Either</code> type takes two type
|
||
arguments. The type <code>Either a b</code> has two constructors:
|
||
<code>Left</code> and <code>Right</code>. Both take an argument,
|
||
<code>Left</code> an argument of type <code>a</code> and
|
||
<code>Right</code> an argument of type <code>b</code>.</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Values</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Either Int Bool</code></td>
|
||
<td style="text-align: left;"><code>Left 0</code>, <code>Left 1</code>,
|
||
<code>Right False</code>, <code>Right True</code>, …</td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>Either String [Int]</code></td>
|
||
<td style="text-align: left;"><code>Left "asdf"</code>,
|
||
<code>Right [0,1,2]</code>, …</td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>Either Integer Integer</code></td>
|
||
<td style="text-align: left;"><code>Left 0</code>, <code>Right 0</code>,
|
||
<code>Left 1</code>, <code>Right 1</code>, …</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>Here’s a simple example: a <code>readInt</code> function that only
|
||
knows a couple of numbers and returns a descriptive error for the rest.
|
||
Note the Haskell convention of using <code>Left</code> for errors and
|
||
<code>Right</code> for success.</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="fu">readInt</span><span class="ot"> ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Either</span> <span class="dt">String</span> <span class="dt">Int</span></span>
|
||
<span id="cb122-2"><a href="#cb122-2" aria-hidden="true" tabindex="-1"></a><span class="fu">readInt</span> <span class="st">"0"</span> <span class="ot">=</span> <span class="dt">Right</span> <span class="dv">0</span></span>
|
||
<span id="cb122-3"><a href="#cb122-3" aria-hidden="true" tabindex="-1"></a><span class="fu">readInt</span> <span class="st">"1"</span> <span class="ot">=</span> <span class="dt">Right</span> <span class="dv">1</span></span>
|
||
<span id="cb122-4"><a href="#cb122-4" aria-hidden="true" tabindex="-1"></a><span class="fu">readInt</span> s <span class="ot">=</span> <span class="dt">Left</span> (<span class="st">"Unsupported string: "</span> <span class="op">++</span> s)</span></code></pre></div>
|
||
<p>Sidenote: the constructors of <code>Either</code> are called
|
||
<code>Left</code> and <code>Right</code> because they refer to the left
|
||
and right type arguments of <code>Either</code>. Note how in
|
||
<code>Either a b</code>, <code>a</code> is the left argument and
|
||
<code>b</code> is the right argument. Thus <code>Left</code> contains a
|
||
value of type <code>a</code> and likewise <code>Right</code> of type
|
||
<code>b</code>. The convention of using <code>Right</code> for success
|
||
is probably simply because right also means correct. No offense is
|
||
intended to left-handed people.</p>
|
||
<p>Here’s another example: pattern matching an <code>Either</code>. Just
|
||
like with <code>Maybe</code>, there are two patterns for an
|
||
<code>Either</code>, one for each constructor.</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="ot">iWantAString ::</span> <span class="dt">Either</span> <span class="dt">Int</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb123-2"><a href="#cb123-2" aria-hidden="true" tabindex="-1"></a>iWantAString (<span class="dt">Right</span> str) <span class="ot">=</span> str</span>
|
||
<span id="cb123-3"><a href="#cb123-3" aria-hidden="true" tabindex="-1"></a>iWantAString (<span class="dt">Left</span> number) <span class="ot">=</span> <span class="fu">show</span> number</span></code></pre></div>
|
||
<p>As you recall, Haskell lists can only contain elements of the same
|
||
type. You can’t have a value like <code>[1,"foo",2]</code>. However, you
|
||
can use a type like <code>Either</code> to represent lists that can
|
||
contain two different types of values. For example we could track the
|
||
number of people on a lecture, with a possibility of adding an
|
||
explanation if a value is missing:</p>
|
||
<pre><code>lectureParticipants :: [Either String Int]
|
||
lectureParticipants = [Right 10, Right 13, Left "easter vacation", Right 17, Left "lecturer was sick", Right 3]</code></pre>
|
||
<h2 data-number="2.9" id="the-case-of-expression"><span
|
||
class="header-section-number">2.9</span> The case-of Expression</h2>
|
||
<p>We’ve seen pattern matching in function arguments, but there’s also a
|
||
way to pattern match in an expression. It looks like this:</p>
|
||
<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="kw">case</span> <span class="op"><</span>value<span class="op">></span> <span class="kw">of</span> <span class="op"><</span><span class="kw">pattern</span><span class="op">></span> <span class="ot">-></span> <span class="op"><</span>expression<span class="op">></span></span>
|
||
<span id="cb125-2"><a href="#cb125-2" aria-hidden="true" tabindex="-1"></a> <span class="op"><</span><span class="kw">pattern</span><span class="op">></span> <span class="ot">-></span> <span class="op"><</span>expression<span class="op">></span></span></code></pre></div>
|
||
<p>As an example let’s rewrite the <code>describe</code> example from
|
||
the first lecture using <code>case</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">describe ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb126-2"><a href="#cb126-2" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">0</span> <span class="ot">=</span> <span class="st">"zero"</span></span>
|
||
<span id="cb126-3"><a href="#cb126-3" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">1</span> <span class="ot">=</span> <span class="st">"one"</span></span>
|
||
<span id="cb126-4"><a href="#cb126-4" aria-hidden="true" tabindex="-1"></a>describe <span class="dv">2</span> <span class="ot">=</span> <span class="st">"an even prime"</span></span>
|
||
<span id="cb126-5"><a href="#cb126-5" aria-hidden="true" tabindex="-1"></a>describe n <span class="ot">=</span> <span class="st">"the number "</span> <span class="op">++</span> <span class="fu">show</span> n</span></code></pre></div>
|
||
<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="ot">describe ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb127-2"><a href="#cb127-2" aria-hidden="true" tabindex="-1"></a>describe n <span class="ot">=</span> <span class="kw">case</span> n <span class="kw">of</span> <span class="dv">0</span> <span class="ot">-></span> <span class="st">"zero"</span></span>
|
||
<span id="cb127-3"><a href="#cb127-3" aria-hidden="true" tabindex="-1"></a> <span class="dv">1</span> <span class="ot">-></span> <span class="st">"one"</span></span>
|
||
<span id="cb127-4"><a href="#cb127-4" aria-hidden="true" tabindex="-1"></a> <span class="dv">2</span> <span class="ot">-></span> <span class="st">"an even prime"</span></span>
|
||
<span id="cb127-5"><a href="#cb127-5" aria-hidden="true" tabindex="-1"></a> n <span class="ot">-></span> <span class="st">"the number "</span> <span class="op">++</span> <span class="fu">show</span> n</span></code></pre></div>
|
||
<p>A more interesting example is when the value we’re pattern matching
|
||
on is not a function argument. For example:</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="co">-- parse country code into country name, returns Nothing if code not recognized</span></span>
|
||
<span id="cb128-2"><a href="#cb128-2" aria-hidden="true" tabindex="-1"></a><span class="ot">parseCountry ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">String</span></span>
|
||
<span id="cb128-3"><a href="#cb128-3" aria-hidden="true" tabindex="-1"></a>parseCountry <span class="st">"FI"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="st">"Finland"</span></span>
|
||
<span id="cb128-4"><a href="#cb128-4" aria-hidden="true" tabindex="-1"></a>parseCountry <span class="st">"SE"</span> <span class="ot">=</span> <span class="dt">Just</span> <span class="st">"Sweden"</span></span>
|
||
<span id="cb128-5"><a href="#cb128-5" aria-hidden="true" tabindex="-1"></a>parseCountry _ <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb128-6"><a href="#cb128-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb128-7"><a href="#cb128-7" aria-hidden="true" tabindex="-1"></a><span class="ot">flyTo ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb128-8"><a href="#cb128-8" aria-hidden="true" tabindex="-1"></a>flyTo countryCode <span class="ot">=</span> <span class="kw">case</span> parseCountry countryCode <span class="kw">of</span> <span class="dt">Just</span> country <span class="ot">-></span> <span class="st">"You're flying to "</span> <span class="op">++</span> country</span>
|
||
<span id="cb128-9"><a href="#cb128-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> <span class="st">"You're not flying anywhere"</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> flyTo <span class="st">"FI"</span></span>
|
||
<span id="cb129-2"><a href="#cb129-2" aria-hidden="true" tabindex="-1"></a><span class="st">"You're flying to Finland"</span></span>
|
||
<span id="cb129-3"><a href="#cb129-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> flyTo <span class="st">"DE"</span></span>
|
||
<span id="cb129-4"><a href="#cb129-4" aria-hidden="true" tabindex="-1"></a><span class="st">"You're not flying anywhere"</span></span></code></pre></div>
|
||
<p>We could write the <code>flyTo</code> function using a helper
|
||
function for pattern matching instead of using the case-of
|
||
expression:</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">flyTo ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb130-2"><a href="#cb130-2" aria-hidden="true" tabindex="-1"></a>flyTo countryCode <span class="ot">=</span> handleResult (parseCountry countryCode)</span>
|
||
<span id="cb130-3"><a href="#cb130-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> handleResult (<span class="dt">Just</span> country) <span class="ot">=</span> <span class="st">"You're flying to "</span> <span class="op">++</span> country</span>
|
||
<span id="cb130-4"><a href="#cb130-4" aria-hidden="true" tabindex="-1"></a> handleResult <span class="dt">Nothing</span> <span class="ot">=</span> <span class="st">"You're not flying anywhere"</span></span></code></pre></div>
|
||
<p>In fact, a case-of expression can always be replaced with a helper
|
||
function. Here’s one more example, written in both ways:</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="co">-- given a sentence, decide whether it is a statement, question or exclamation</span></span>
|
||
<span id="cb131-2"><a href="#cb131-2" aria-hidden="true" tabindex="-1"></a><span class="ot">sentenceType ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb131-3"><a href="#cb131-3" aria-hidden="true" tabindex="-1"></a>sentenceType sentence <span class="ot">=</span> <span class="kw">case</span> <span class="fu">last</span> sentence <span class="kw">of</span> <span class="ch">'.'</span> <span class="ot">-></span> <span class="st">"statement"</span></span>
|
||
<span id="cb131-4"><a href="#cb131-4" aria-hidden="true" tabindex="-1"></a> <span class="ch">'?'</span> <span class="ot">-></span> <span class="st">"question"</span></span>
|
||
<span id="cb131-5"><a href="#cb131-5" aria-hidden="true" tabindex="-1"></a> <span class="ch">'!'</span> <span class="ot">-></span> <span class="st">"exclamation"</span></span>
|
||
<span id="cb131-6"><a href="#cb131-6" aria-hidden="true" tabindex="-1"></a> _ <span class="ot">-></span> <span class="st">"not a sentence"</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="co">-- same function, helper function instead of case-of</span></span>
|
||
<span id="cb132-2"><a href="#cb132-2" aria-hidden="true" tabindex="-1"></a>sentenceType sentence <span class="ot">=</span> classify (<span class="fu">last</span> sentence)</span>
|
||
<span id="cb132-3"><a href="#cb132-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> classify <span class="ch">'.'</span> <span class="ot">=</span> <span class="st">"statement"</span></span>
|
||
<span id="cb132-4"><a href="#cb132-4" aria-hidden="true" tabindex="-1"></a> classify <span class="ch">'?'</span> <span class="ot">=</span> <span class="st">"question"</span></span>
|
||
<span id="cb132-5"><a href="#cb132-5" aria-hidden="true" tabindex="-1"></a> classify <span class="ch">'!'</span> <span class="ot">=</span> <span class="st">"exclamation"</span></span>
|
||
<span id="cb132-6"><a href="#cb132-6" aria-hidden="true" tabindex="-1"></a> classify _ <span class="ot">=</span> <span class="st">"not a sentence"</span></span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> sentenceType <span class="st">"This is Haskell."</span></span>
|
||
<span id="cb133-2"><a href="#cb133-2" aria-hidden="true" tabindex="-1"></a><span class="st">"statement"</span></span>
|
||
<span id="cb133-3"><a href="#cb133-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> sentenceType <span class="st">"This is Haskell!"</span></span>
|
||
<span id="cb133-4"><a href="#cb133-4" aria-hidden="true" tabindex="-1"></a><span class="st">"exclamation"</span></span></code></pre></div>
|
||
<h3 data-number="2.9.1" id="when-to-use-case-expressions"><span
|
||
class="header-section-number">2.9.1</span> When to Use Case
|
||
Expressions</h3>
|
||
<p>You might be asking, what is the point of having another pattern
|
||
matching syntax. Well, <code>case</code> expressions have some
|
||
advantages over equations which we’ll discuss next.</p>
|
||
<p>Firstly, and perhaps most importantly, <code>case</code> expressions
|
||
enable us to pattern match against function outputs. We might want to
|
||
write early morning motivational messages to working (lazy)
|
||
Haskellers:</p>
|
||
<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="ot">motivate ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb134-2"><a href="#cb134-2" aria-hidden="true" tabindex="-1"></a>motivate <span class="st">"Monday"</span> <span class="ot">=</span> <span class="st">"Have a nice week at work!"</span></span>
|
||
<span id="cb134-3"><a href="#cb134-3" aria-hidden="true" tabindex="-1"></a>motivate <span class="st">"Tuesday"</span> <span class="ot">=</span> <span class="st">"You're one day closer to weekend!"</span></span>
|
||
<span id="cb134-4"><a href="#cb134-4" aria-hidden="true" tabindex="-1"></a>motivate <span class="st">"Wednesday"</span> <span class="ot">=</span> <span class="st">"3 more day(s) until the weekend!"</span></span>
|
||
<span id="cb134-5"><a href="#cb134-5" aria-hidden="true" tabindex="-1"></a>motivate <span class="st">"Thursday"</span> <span class="ot">=</span> <span class="st">"2 more day(s) until the weekend!"</span></span>
|
||
<span id="cb134-6"><a href="#cb134-6" aria-hidden="true" tabindex="-1"></a>motivate <span class="st">"Friday"</span> <span class="ot">=</span> <span class="st">"1 more day(s) until the weekend!"</span></span>
|
||
<span id="cb134-7"><a href="#cb134-7" aria-hidden="true" tabindex="-1"></a>motivate _ <span class="ot">=</span> <span class="st">"Relax! You don't need to work today!"</span></span></code></pre></div>
|
||
<p>Using a <code>case</code> expression we can run a helper function
|
||
against the argument and pattern match on the result:</p>
|
||
<div class="sourceCode" id="cb135"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb135-1"><a href="#cb135-1" aria-hidden="true" tabindex="-1"></a><span class="ot">motivate ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb135-2"><a href="#cb135-2" aria-hidden="true" tabindex="-1"></a>motivate day <span class="ot">=</span> <span class="kw">case</span> distanceToSunday day <span class="kw">of</span></span>
|
||
<span id="cb135-3"><a href="#cb135-3" aria-hidden="true" tabindex="-1"></a> <span class="dv">6</span> <span class="ot">-></span> <span class="st">"Have a nice week at work!"</span></span>
|
||
<span id="cb135-4"><a href="#cb135-4" aria-hidden="true" tabindex="-1"></a> <span class="dv">5</span> <span class="ot">-></span> <span class="st">"You're one day closer to weekend!"</span></span>
|
||
<span id="cb135-5"><a href="#cb135-5" aria-hidden="true" tabindex="-1"></a> n <span class="ot">-></span> <span class="kw">if</span> n <span class="op">></span> <span class="dv">1</span></span>
|
||
<span id="cb135-6"><a href="#cb135-6" aria-hidden="true" tabindex="-1"></a> <span class="kw">then</span> <span class="fu">show</span> (n <span class="op">-</span> <span class="dv">1</span>) <span class="op">++</span> <span class="st">" more day(s) until the weekend!"</span></span>
|
||
<span id="cb135-7"><a href="#cb135-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">else</span> <span class="st">"Relax! You don't need to work today!"</span></span></code></pre></div>
|
||
<p>By the way, there’s also a third way, guards:</p>
|
||
<div class="sourceCode" id="cb136"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb136-1"><a href="#cb136-1" aria-hidden="true" tabindex="-1"></a><span class="ot">motivate ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb136-2"><a href="#cb136-2" aria-hidden="true" tabindex="-1"></a>motivate day</span>
|
||
<span id="cb136-3"><a href="#cb136-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n <span class="op">==</span> <span class="dv">6</span> <span class="ot">=</span> <span class="st">"Have a nice week at work!"</span></span>
|
||
<span id="cb136-4"><a href="#cb136-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n <span class="op">==</span> <span class="dv">5</span> <span class="ot">=</span> <span class="st">"You're one day closer to weekend!"</span></span>
|
||
<span id="cb136-5"><a href="#cb136-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> n <span class="op">></span> <span class="dv">1</span> <span class="ot">=</span> <span class="fu">show</span> (n <span class="op">-</span> <span class="dv">1</span>) <span class="op">++</span> <span class="st">" more day(s) until the weekend!"</span></span>
|
||
<span id="cb136-6"><a href="#cb136-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="st">"Relax! You don't need to work today!"</span></span>
|
||
<span id="cb136-7"><a href="#cb136-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> n <span class="ot">=</span> distanceToSunday day</span></code></pre></div>
|
||
<p>We’ll see in a moment how we can define <code>distanceToSunday</code>
|
||
using equations and <code>case</code> expressions.</p>
|
||
<p>Secondly, if a helper function needs to be shared among many
|
||
patterns, then equations don’t work. For example:</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="ot">area ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb137-2"><a href="#cb137-2" aria-hidden="true" tabindex="-1"></a>area <span class="st">"square"</span> x <span class="ot">=</span> square x</span>
|
||
<span id="cb137-3"><a href="#cb137-3" aria-hidden="true" tabindex="-1"></a>area <span class="st">"circle"</span> x <span class="ot">=</span> <span class="fu">pi</span> <span class="op">*</span> square x</span>
|
||
<span id="cb137-4"><a href="#cb137-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> square x <span class="ot">=</span> x <span class="op">*</span> x</span></code></pre></div>
|
||
<p>This won’t compile because a the <code>where</code> clause only
|
||
appends to the <code>"circle"</code> case, so the <code>square</code>
|
||
helper function is not available in the <code>"square"</code> case. On
|
||
the other hand, we can write</p>
|
||
<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="ot">area ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb138-2"><a href="#cb138-2" aria-hidden="true" tabindex="-1"></a>area shape x <span class="ot">=</span> <span class="kw">case</span> shape <span class="kw">of</span></span>
|
||
<span id="cb138-3"><a href="#cb138-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"square"</span> <span class="ot">-></span> square x</span>
|
||
<span id="cb138-4"><a href="#cb138-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"circle"</span> <span class="ot">-></span> <span class="fu">pi</span> <span class="op">*</span> square x</span>
|
||
<span id="cb138-5"><a href="#cb138-5" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> square x <span class="ot">=</span> x<span class="op">*</span>x</span></code></pre></div>
|
||
<p>Thirdly, <code>case</code> expressions may help to write more concise
|
||
code in a situation where a (long) function name would have to be
|
||
repeated multiple times using equations. As we saw above, we might need
|
||
a function which measures the distance between a given day and
|
||
Sunday:</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="ot">distanceToSunday ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb139-2"><a href="#cb139-2" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Monday"</span> <span class="ot">=</span> <span class="dv">6</span></span>
|
||
<span id="cb139-3"><a href="#cb139-3" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Tuesday"</span> <span class="ot">=</span> <span class="dv">5</span></span>
|
||
<span id="cb139-4"><a href="#cb139-4" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Wednesday"</span> <span class="ot">=</span> <span class="dv">4</span></span>
|
||
<span id="cb139-5"><a href="#cb139-5" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Thursday"</span> <span class="ot">=</span> <span class="dv">3</span></span>
|
||
<span id="cb139-6"><a href="#cb139-6" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Friday"</span> <span class="ot">=</span> <span class="dv">2</span></span>
|
||
<span id="cb139-7"><a href="#cb139-7" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Saturday"</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb139-8"><a href="#cb139-8" aria-hidden="true" tabindex="-1"></a>distanceToSunday <span class="st">"Sunday"</span> <span class="ot">=</span> <span class="dv">0</span></span></code></pre></div>
|
||
<p>Using a <code>case</code> expression leads into much more concise
|
||
implementation:</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><span class="ot">distanceToSunday ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb140-2"><a href="#cb140-2" aria-hidden="true" tabindex="-1"></a>distanceToSunday d <span class="ot">=</span> <span class="kw">case</span> d <span class="kw">of</span></span>
|
||
<span id="cb140-3"><a href="#cb140-3" aria-hidden="true" tabindex="-1"></a> <span class="st">"Monday"</span> <span class="ot">-></span> <span class="dv">6</span></span>
|
||
<span id="cb140-4"><a href="#cb140-4" aria-hidden="true" tabindex="-1"></a> <span class="st">"Tuesday"</span> <span class="ot">-></span> <span class="dv">5</span></span>
|
||
<span id="cb140-5"><a href="#cb140-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"Wednesday"</span> <span class="ot">-></span> <span class="dv">4</span></span>
|
||
<span id="cb140-6"><a href="#cb140-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"Thursday"</span> <span class="ot">-></span> <span class="dv">3</span></span>
|
||
<span id="cb140-7"><a href="#cb140-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"Friday"</span> <span class="ot">-></span> <span class="dv">2</span></span>
|
||
<span id="cb140-8"><a href="#cb140-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"Saturday"</span> <span class="ot">-></span> <span class="dv">1</span></span>
|
||
<span id="cb140-9"><a href="#cb140-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"Sunday"</span> <span class="ot">-></span> <span class="dv">0</span></span></code></pre></div>
|
||
<p>These three benefits make the <code>case</code> expression a
|
||
versatile tool in a Haskeller’s toolbox. It’s worth remembering how
|
||
<code>case</code> works.</p>
|
||
<p>(Representing weekdays as strings may get the job done, but it’s not
|
||
the perfect solution. What happens if we apply <code>motivate</code> to
|
||
<code>"monday"</code> (with all letters in lower case) or
|
||
<code>"keskiviikko"</code>? In Lecture 5, we will learn a better way to
|
||
represent things like weekdays.)</p>
|
||
<h2 data-number="2.10" id="recap-pattern-matching"><span
|
||
class="header-section-number">2.10</span> Recap: Pattern Matching</h2>
|
||
<p>Things you can use as patterns:</p>
|
||
<ul>
|
||
<li><code>Int</code> and <code>Integer</code> constants like
|
||
<code>(-1)</code>, <code>0</code>, <code>1</code>, <code>2</code>,
|
||
…</li>
|
||
<li><code>Bool</code> values <code>True</code> and
|
||
<code>False</code></li>
|
||
<li><code>Char</code> constants: <code>'a'</code>, <code>'b'</code></li>
|
||
<li><code>String</code> constants: <code>"abc"</code>,
|
||
<code>""</code></li>
|
||
<li><code>Maybe</code> constructors: <code>Nothing</code>,
|
||
<code>(Just x)</code></li>
|
||
<li><code>Either</code> constructors: <code>(Left x)</code>,
|
||
<code>(Right y)</code></li>
|
||
<li>The special <code>_</code> pattern which means “anything, I don’t
|
||
care”</li>
|
||
<li>Combinations of these patterns, like for example
|
||
<code>(Just 1)</code></li>
|
||
<li>We’ll learn about other patterns, for example lists, in the next
|
||
lectures.</li>
|
||
</ul>
|
||
<p>Places where you can use patterns:</p>
|
||
<ul>
|
||
<li>Defining a function with equations:</li>
|
||
</ul>
|
||
<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><span class="ot">f ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb141-2"><a href="#cb141-2" aria-hidden="true" tabindex="-1"></a>f <span class="dt">False</span> <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb141-3"><a href="#cb141-3" aria-hidden="true" tabindex="-1"></a>f <span class="dt">False</span> _ <span class="ot">=</span> <span class="dv">2</span></span>
|
||
<span id="cb141-4"><a href="#cb141-4" aria-hidden="true" tabindex="-1"></a>f <span class="dt">True</span> (<span class="dt">Just</span> i) <span class="ot">=</span> i</span>
|
||
<span id="cb141-5"><a href="#cb141-5" aria-hidden="true" tabindex="-1"></a>f <span class="dt">True</span> <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dv">0</span></span></code></pre></div>
|
||
<ul>
|
||
<li>In the <code>case of</code> expression:</li>
|
||
</ul>
|
||
<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><span class="kw">case</span> number <span class="kw">of</span> <span class="dv">0</span> <span class="ot">-></span> <span class="st">"zero"</span></span>
|
||
<span id="cb142-2"><a href="#cb142-2" aria-hidden="true" tabindex="-1"></a> <span class="dv">1</span> <span class="ot">-></span> <span class="st">"one"</span></span>
|
||
<span id="cb142-3"><a href="#cb142-3" aria-hidden="true" tabindex="-1"></a> _ <span class="ot">-></span> <span class="st">"not zero or one"</span></span></code></pre></div>
|
||
<p>The only thing you really <em>need</em> pattern matching for is
|
||
<em>getting the value</em> inside a <code>Just</code>, <code>Left</code>
|
||
or <code>Right</code> constructor. Here are two more examples of
|
||
this:</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="co">-- getElement (Just i) gets the ith element (counting from zero) of a list, getElement Nothing gets the last element</span></span>
|
||
<span id="cb143-2"><a href="#cb143-2" aria-hidden="true" tabindex="-1"></a><span class="ot">getElement ::</span> <span class="dt">Maybe</span> <span class="dt">Int</span> <span class="ot">-></span> [a] <span class="ot">-></span> a</span>
|
||
<span id="cb143-3"><a href="#cb143-3" aria-hidden="true" tabindex="-1"></a>getElement (<span class="dt">Just</span> i) xs <span class="ot">=</span> xs <span class="op">!!</span> i</span>
|
||
<span id="cb143-4"><a href="#cb143-4" aria-hidden="true" tabindex="-1"></a>getElement <span class="dt">Nothing</span> xs <span class="ot">=</span> <span class="fu">last</span> xs</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> getElement <span class="dt">Nothing</span> <span class="st">"hurray!"</span></span>
|
||
<span id="cb144-2"><a href="#cb144-2" aria-hidden="true" tabindex="-1"></a><span class="ch">'!'</span></span>
|
||
<span id="cb144-3"><a href="#cb144-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> getElement (<span class="dt">Just</span> <span class="dv">3</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>
|
||
<span id="cb144-4"><a href="#cb144-4" aria-hidden="true" tabindex="-1"></a><span class="dv">8</span></span></code></pre></div>
|
||
<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">direction ::</span> <span class="dt">Either</span> <span class="dt">Int</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb145-2"><a href="#cb145-2" aria-hidden="true" tabindex="-1"></a>direction (<span class="dt">Left</span> i) <span class="ot">=</span> <span class="st">"you should go left "</span> <span class="op">++</span> <span class="fu">show</span> i <span class="op">++</span> <span class="st">" meters!"</span></span>
|
||
<span id="cb145-3"><a href="#cb145-3" aria-hidden="true" tabindex="-1"></a>direction (<span class="dt">Right</span> i) <span class="ot">=</span> <span class="st">"you should go right "</span> <span class="op">++</span> <span class="fu">show</span> i <span class="op">++</span> <span class="st">" meters!"</span></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> direction (<span class="dt">Left</span> <span class="dv">3</span>)</span>
|
||
<span id="cb146-2"><a href="#cb146-2" aria-hidden="true" tabindex="-1"></a><span class="st">"you should go left 3 meters!"</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> direction (<span class="dt">Right</span> <span class="dv">5</span>)</span>
|
||
<span id="cb146-4"><a href="#cb146-4" aria-hidden="true" tabindex="-1"></a><span class="st">"you should go right 5 meters!"</span></span></code></pre></div>
|
||
<p>Other uses (that we’ve seen so far!) of pattern matching can also be
|
||
accomplished with the <code>==</code> operator. However, things like
|
||
<code>x==Nothing</code> won’t work in all cases. We’ll find out why when
|
||
we talk about type classes in lecture 4.</p>
|
||
<h2 data-number="2.11" id="quiz-1"><span
|
||
class="header-section-number">2.11</span> Quiz</h2>
|
||
<p>How many values does <code>f x = [x,x]</code> return?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
Zero
|
||
<li class="correct">
|
||
One
|
||
</li>
|
||
<li>
|
||
Two
|
||
</ol>
|
||
<p>Why does the expression <code>Nothing 1</code> cause a type
|
||
error?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
Because <code>Nothing</code> takes no arguments
|
||
</li>
|
||
<li>
|
||
Because <code>Nothing</code> returns nothing
|
||
</li>
|
||
<li>
|
||
Because <code>Nothing</code> is a constructor
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of the function
|
||
<code>f x y = if x && y then Right x else Left "foo"</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Bool -> Bool -> Either Bool String</code>
|
||
</li>
|
||
<li>
|
||
<code>String -> String -> Either String String</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Bool -> Bool -> Either String Bool</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which of the following functions could have the type
|
||
<code>Bool -> Int -> [Bool]</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>f x y = [0, y]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>f x y = [x, True]</code>
|
||
</li>
|
||
<li>
|
||
<code>f x y = [y, True]</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of this function?
|
||
<code>justBoth a b = [Just a, Just b]</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>a -> b -> [Maybe a, Maybe b]</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> a -> [Just a]</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> b -> [Maybe a]</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>a -> a -> [Maybe a]</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="2.12" id="exercises-1"><span
|
||
class="header-section-number">2.12</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set2a.hs">Set2a</a></li>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set2b.hs">Set2b</a></li>
|
||
</ul>
|
||
<h1 data-number="3" id="lecture-3-catamorphic"><span
|
||
class="header-section-number">3</span> Lecture 3: Catamorphic</h1>
|
||
<!-- TODO name of lecture is too obscure, and also folds are only introduced in Lecture 4 -->
|
||
<ul>
|
||
<li>Lists, lists, lists</li>
|
||
<li>Functionality</li>
|
||
<li>A bit about types</li>
|
||
</ul>
|
||
<h2 data-number="3.1" id="functional-programming-at-last"><span
|
||
class="header-section-number">3.1</span> Functional Programming, at
|
||
Last</h2>
|
||
<p>Now with lists and polymorphism in our toolbox, we can finally start
|
||
to look at functional programming.</p>
|
||
<p>In Haskell a function is a value, just like a number or a list is.
|
||
Functions can be passed as parameters to other functions. Here’s a toy
|
||
example. The function <code>applyTo1</code> takes a function of type
|
||
<code>Int->Int</code>, applies it to the number <code>1</code>, and
|
||
returns the result.</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">applyTo1 ::</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="cb147-2"><a href="#cb147-2" aria-hidden="true" tabindex="-1"></a>applyTo1 f <span class="ot">=</span> f <span class="dv">1</span></span></code></pre></div>
|
||
<p>Let’s define a simple function of type <code>Int->Int</code> and
|
||
see <code>applyTo1</code> in action.</p>
|
||
<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="ot">addThree ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb148-2"><a href="#cb148-2" aria-hidden="true" tabindex="-1"></a>addThree x <span class="ot">=</span> x <span class="op">+</span> <span class="dv">3</span></span></code></pre></div>
|
||
<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>applyTo1 addThree</span>
|
||
<span id="cb149-2"><a href="#cb149-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> addThree <span class="dv">1</span></span>
|
||
<span id="cb149-3"><a href="#cb149-3" 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>
|
||
<span id="cb149-4"><a href="#cb149-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">4</span></span></code></pre></div>
|
||
<p>Let’s go back to the type annotation for <code>applyTo1</code>.</p>
|
||
<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="ot">applyTo1 ::</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></code></pre></div>
|
||
<p>The parentheses are needed because the type
|
||
<code>Int -> Int -> Int</code> would be the type of a function
|
||
taking two <code>Int</code> arguments. More on this later.</p>
|
||
<p>Let’s look at a slightly more interesting example. This time we’ll
|
||
implement a polymorphic function <code>doTwice</code>. Note how we can
|
||
use it with various types of values and functions.</p>
|
||
<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">doTwice ::</span> (a <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb151-2"><a href="#cb151-2" aria-hidden="true" tabindex="-1"></a>doTwice f x <span class="ot">=</span> f (f x)</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>doTwice addThree <span class="dv">1</span></span>
|
||
<span id="cb152-2"><a href="#cb152-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> addThree (addThree <span class="dv">1</span>)</span>
|
||
<span id="cb152-3"><a href="#cb152-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">7</span></span>
|
||
<span id="cb152-4"><a href="#cb152-4" aria-hidden="true" tabindex="-1"></a>doTwice <span class="fu">tail</span> <span class="st">"abcd"</span></span>
|
||
<span id="cb152-5"><a href="#cb152-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="fu">tail</span> (<span class="fu">tail</span> <span class="st">"abcd"</span>)</span>
|
||
<span id="cb152-6"><a href="#cb152-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="st">"cd"</span></span></code></pre></div>
|
||
<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="ot">makeCool ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb153-2"><a href="#cb153-2" aria-hidden="true" tabindex="-1"></a>makeCool str <span class="ot">=</span> <span class="st">"WOW "</span> <span class="op">++</span> str <span class="op">++</span> <span class="st">"!"</span></span></code></pre></div>
|
||
<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>doTwice makeCool <span class="st">"Haskell"</span></span>
|
||
<span id="cb154-2"><a href="#cb154-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="st">"WOW WOW Haskell!!"</span></span></code></pre></div>
|
||
<h3 data-number="3.1.1" id="functional-programming-on-lists"><span
|
||
class="header-section-number">3.1.1</span> Functional Programming on
|
||
Lists</h3>
|
||
<p>That was a bit boring. Luckily there are many useful list functions
|
||
that take functions as arguments. By the way, functions that take
|
||
functions as arguments (or return functions) are often called
|
||
<em>higher-order functions</em>.</p>
|
||
<p>The most famous of these list-processing higher-order functions is
|
||
<code>map</code>. It gives you a new list by applying the given function
|
||
to all elements of a list.</p>
|
||
<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><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></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="fu">map</span> addThree [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb156-2"><a href="#cb156-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span>]</span></code></pre></div>
|
||
<p>The partner in crime for <code>map</code> is <code>filter</code>.
|
||
Instead of transforming all elements of a list, <code>filter</code>
|
||
drops some elements of a list and keeps others. In other words,
|
||
<code>filter</code> selects the elements from a list that fulfill a
|
||
condition.</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="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></code></pre></div>
|
||
<p>Here’s an example: selecting the positive elements from a list</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="ot">positive ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb158-2"><a href="#cb158-2" aria-hidden="true" tabindex="-1"></a>positive x <span class="ot">=</span> x<span class="op">></span><span class="dv">0</span></span></code></pre></div>
|
||
<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="fu">filter</span> positive [<span class="dv">0</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">1</span>,<span class="dv">3</span>,<span class="op">-</span><span class="dv">3</span>]</span>
|
||
<span id="cb159-2"><a href="#cb159-2" 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>Note how both the type signatures of <code>map</code> and
|
||
<code>filter</code> use polymorphism. They work on all kinds of lists.
|
||
The type of <code>map</code> even uses two type parameters! Here are
|
||
some examples of type inference using <code>map</code> and
|
||
<code>filter</code>.</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>onlyPositive xs <span class="ot">=</span> <span class="fu">filter</span> positive xs</span>
|
||
<span id="cb160-2"><a href="#cb160-2" aria-hidden="true" tabindex="-1"></a>mapBooleans f <span class="ot">=</span> <span class="fu">map</span> f [<span class="dt">False</span>,<span class="dt">True</span>]</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t onlyPositive</span>
|
||
<span id="cb161-2"><a href="#cb161-2" aria-hidden="true" tabindex="-1"></a><span class="ot">onlyPositive ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb161-3"><a href="#cb161-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t mapBooleans</span>
|
||
<span id="cb161-4"><a href="#cb161-4" aria-hidden="true" tabindex="-1"></a><span class="ot">mapBooleans ::</span> (<span class="dt">Bool</span> <span class="ot">-></span> b) <span class="ot">-></span> [b]</span>
|
||
<span id="cb161-5"><a href="#cb161-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t mapBooleans <span class="fu">not</span></span>
|
||
<span id="cb161-6"><a href="#cb161-6" aria-hidden="true" tabindex="-1"></a>mapBooleans<span class="ot"> not ::</span> [<span class="dt">Bool</span>]</span></code></pre></div>
|
||
<p>One more thing: remember how constructors were just functions? That
|
||
means you can pass them as arguments to other functions!</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>wrapJust xs <span class="ot">=</span> <span class="fu">map</span> <span class="dt">Just</span> xs</span></code></pre></div>
|
||
<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> <span class="op">:</span>t wrapJust</span>
|
||
<span id="cb163-2"><a href="#cb163-2" aria-hidden="true" tabindex="-1"></a><span class="ot">wrapJust ::</span> [a] <span class="ot">-></span> [<span class="dt">Maybe</span> a]</span>
|
||
<span id="cb163-3"><a href="#cb163-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> wrapJust [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb163-4"><a href="#cb163-4" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Just</span> <span class="dv">1</span>,<span class="dt">Just</span> <span class="dv">2</span>,<span class="dt">Just</span> <span class="dv">3</span>]</span></code></pre></div>
|
||
<h3 data-number="3.1.2"
|
||
id="examples-of-functional-programming-on-lists"><span
|
||
class="header-section-number">3.1.2</span> Examples of Functional
|
||
Programming on Lists</h3>
|
||
<p>How many “palindrome numbers” are between <code>1</code> and
|
||
<code>n</code>?</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="co">-- a predicate that checks if a string is a palindrome</span></span>
|
||
<span id="cb164-2"><a href="#cb164-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="cb164-3"><a href="#cb164-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="cb164-4"><a href="#cb164-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb164-5"><a href="#cb164-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- palindromes n takes all numbers from 1 to n, converts them to strings using show, and keeps only palindromes</span></span>
|
||
<span id="cb164-6"><a href="#cb164-6" 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="cb164-7"><a href="#cb164-7" 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="cb165"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb165-1"><a href="#cb165-1" aria-hidden="true" tabindex="-1"></a>palindrome <span class="st">"1331"</span> <span class="op">==></span> <span class="dt">True</span></span>
|
||
<span id="cb165-2"><a href="#cb165-2" aria-hidden="true" tabindex="-1"></a>palindromes <span class="dv">150</span> <span class="op">==></span></span>
|
||
<span id="cb165-3"><a href="#cb165-3" aria-hidden="true" tabindex="-1"></a> [<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="cb165-4"><a href="#cb165-4" 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="cb165-5"><a href="#cb165-5" 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>
|
||
<span id="cb165-6"><a href="#cb165-6" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (palindromes <span class="dv">9999</span>) <span class="op">==></span> <span class="dv">198</span></span></code></pre></div>
|
||
<p>How many words in a string start with “a”? This uses the function
|
||
<code>words</code> from the module <code>Data.List</code> that splits a
|
||
string into words.</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="ot">countAWords ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb166-2"><a href="#cb166-2" aria-hidden="true" tabindex="-1"></a>countAWords string <span class="ot">=</span> <span class="fu">length</span> (<span class="fu">filter</span> startsWithA (<span class="fu">words</span> string))</span>
|
||
<span id="cb166-3"><a href="#cb166-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> startsWithA s <span class="ot">=</span> <span class="fu">head</span> s <span class="op">==</span> <span class="ch">'a'</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>countAWords <span class="st">"does anyone want an apple?"</span></span>
|
||
<span id="cb167-2"><a href="#cb167-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>The function <code>tails</code> from <code>Data.List</code> returns
|
||
the list of all suffixes (“tails”) of a list. We can use
|
||
<code>tails</code> for many string processing tasks. Here’s how
|
||
<code>tails</code> works:</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>tails <span class="st">"echo"</span></span>
|
||
<span id="cb168-2"><a href="#cb168-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"echo"</span>,<span class="st">"cho"</span>,<span class="st">"ho"</span>,<span class="st">"o"</span>,<span class="st">""</span>]</span></code></pre></div>
|
||
<p>Here’s an example where we find what characters come after a given
|
||
character in a string. First of all, we use <code>tails</code>,
|
||
<code>map</code> and <code>take</code> to get all substrings of a
|
||
certain length:</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="ot">substringsOfLength ::</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="cb169-2"><a href="#cb169-2" aria-hidden="true" tabindex="-1"></a>substringsOfLength n string <span class="ot">=</span> <span class="fu">map</span> shorten (tails string)</span>
|
||
<span id="cb169-3"><a href="#cb169-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> shorten s <span class="ot">=</span> <span class="fu">take</span> n s</span></code></pre></div>
|
||
<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>substringsOfLength <span class="dv">3</span> <span class="st">"hello"</span></span>
|
||
<span id="cb170-2"><a href="#cb170-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"hel"</span>,<span class="st">"ell"</span>,<span class="st">"llo"</span>,<span class="st">"lo"</span>,<span class="st">"o"</span>,<span class="st">""</span>]</span></code></pre></div>
|
||
<p>There’s some shorter substrings left at the end (can you see why?),
|
||
but they’re fine for our purposes right now. Now that we have
|
||
<code>substringsOfLength</code>, we can implement the function
|
||
<code>whatFollows c k s</code> that finds all the occurrences of the
|
||
character <code>c</code> in the string <code>s</code>, and outputs the
|
||
<code>k</code> letters that come after these occurrences.</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">whatFollows ::</span> <span class="dt">Char</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="cb171-2"><a href="#cb171-2" aria-hidden="true" tabindex="-1"></a>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> (<span class="fu">filter</span> match (substringsOfLength (k<span class="op">+</span><span class="dv">1</span>) string))</span>
|
||
<span id="cb171-3"><a href="#cb171-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> match sub <span class="ot">=</span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span></code></pre></div>
|
||
<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>whatFollows <span class="ch">'a'</span> <span class="dv">2</span> <span class="st">"abracadabra"</span></span>
|
||
<span id="cb172-2"><a href="#cb172-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"br"</span>,<span class="st">"ca"</span>,<span class="st">"da"</span>,<span class="st">"br"</span>,<span class="st">""</span>]</span></code></pre></div>
|
||
<h2 data-number="3.2" id="partial-application"><span
|
||
class="header-section-number">3.2</span> Partial Application</h2>
|
||
<p>When using higher-order functions you can find yourself defining lots
|
||
of small helper functions, like <code>addThree</code> or
|
||
<code>shorten</code> in the previous examples. This is a bit of a chore
|
||
in the long run, but luckily Haskell’s functions behave a bit
|
||
weirdly…</p>
|
||
<p>Let’s start in GHCi:</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><span class="dt">Prelude</span><span class="op">></span> add a b <span class="ot">=</span> a<span class="op">+</span>b</span>
|
||
<span id="cb173-2"><a href="#cb173-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> add <span class="dv">1</span> <span class="dv">5</span></span>
|
||
<span id="cb173-3"><a href="#cb173-3" aria-hidden="true" tabindex="-1"></a><span class="dv">6</span></span>
|
||
<span id="cb173-4"><a href="#cb173-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> addThree <span class="ot">=</span> add <span class="dv">3</span></span>
|
||
<span id="cb173-5"><a href="#cb173-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> addThree <span class="dv">2</span></span>
|
||
<span id="cb173-6"><a href="#cb173-6" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span></span></code></pre></div>
|
||
<p>So, we’ve defined <code>add</code>, a function of two arguments, and
|
||
only given it one argument. The result is not a type error but a new
|
||
function. The new function just stores (or remembers) the given
|
||
argument, waits for another argument, and then gives both to
|
||
<code>add</code>.</p>
|
||
<pre><code>Prelude> map addThree [1,2,3]
|
||
[4,5,6]
|
||
Prelude> map (add 3) [1,2,3]
|
||
[4,5,6]</code></pre>
|
||
<p>Here we can see that we don’t even need to give a name to the
|
||
function returned by <code>add 3</code>. We can just use it anywhere
|
||
where a function of one argument is expected.</p>
|
||
<p>This is called <em>partial application</em>. All functions in Haskell
|
||
behave like this. Let’s have a closer look. Here’s a function that takes
|
||
many arguments.</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><span class="ot">between ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb175-2"><a href="#cb175-2" aria-hidden="true" tabindex="-1"></a>between lo high x <span class="ot">=</span> x <span class="op"><</span> high <span class="op">&&</span> x <span class="op">></span> lo</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> between <span class="dv">3</span> <span class="dv">7</span> <span class="dv">5</span></span>
|
||
<span id="cb176-2"><a href="#cb176-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb176-3"><a href="#cb176-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> between <span class="dv">3</span> <span class="dv">6</span> <span class="dv">8</span></span>
|
||
<span id="cb176-4"><a href="#cb176-4" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span></code></pre></div>
|
||
<p>We can give <code>between</code> less arguments and get back new
|
||
functions, just like we saw with <code>add</code>:</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="dt">Prelude</span><span class="op">></span> (between <span class="dv">1</span> <span class="dv">5</span>) <span class="dv">2</span></span>
|
||
<span id="cb177-2"><a href="#cb177-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb177-3"><a href="#cb177-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="kw">let</span> f <span class="ot">=</span> between <span class="dv">1</span> <span class="dv">5</span> <span class="kw">in</span> f <span class="dv">2</span></span>
|
||
<span id="cb177-4"><a href="#cb177-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb177-5"><a href="#cb177-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</span> (between <span class="dv">1</span> <span class="dv">3</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="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>]</span></code></pre></div>
|
||
<p>Look at the types of partially applying <code>between</code>. They
|
||
behave neatly, with arguments disappearing one by one from the type as
|
||
values are added to the expression.</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t between</span>
|
||
<span id="cb178-2"><a href="#cb178-2" aria-hidden="true" tabindex="-1"></a><span class="ot">between ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb178-3"><a href="#cb178-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t between <span class="dv">1</span></span>
|
||
<span id="cb178-4"><a href="#cb178-4" aria-hidden="true" tabindex="-1"></a>between <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb178-5"><a href="#cb178-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t between <span class="dv">1</span> <span class="dv">2</span></span>
|
||
<span id="cb178-6"><a href="#cb178-6" aria-hidden="true" tabindex="-1"></a>between <span class="dv">1</span> <span class="dv">2</span><span class="ot"> ::</span> <span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb178-7"><a href="#cb178-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t between <span class="dv">1</span> <span class="dv">2</span> <span class="dv">3</span></span>
|
||
<span id="cb178-8"><a href="#cb178-8" aria-hidden="true" tabindex="-1"></a>between <span class="dv">1</span> <span class="dv">2</span> <span class="dv">3</span><span class="ot"> ::</span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<p>Actually, when we write a type like
|
||
<code>Integer -> Integer -> Integer -> Bool</code>, it means
|
||
<code>Integer -> (Integer -> (Integer -> Bool))</code>. That
|
||
is, a multi-argument function is just a function that returns a
|
||
function. Similarly, an expression like <code>between 1 2 3</code> is
|
||
the same as <code>((between 1) 2) 3</code>, so passing multiple
|
||
arguments to a function happens via multiple single-argument calls.
|
||
Representing multi-argument functions like this is called
|
||
<em>currying</em> (after the logician Haskell Curry). Currying is what
|
||
makes partial application possible.</p>
|
||
<p>Here’s another example of using partial application with
|
||
<code>map</code>:</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="fu">map</span> (<span class="fu">drop</span> <span class="dv">1</span>) [<span class="st">"Hello"</span>,<span class="st">"World!"</span>]</span>
|
||
<span id="cb179-2"><a href="#cb179-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"ello"</span>,<span class="st">"orld!"</span>]</span></code></pre></div>
|
||
<p>In addition to normal functions, partial application also works with
|
||
operators. With operators you can choose whether you apply the left or
|
||
the right argument. (Partially applied operators are also called
|
||
<em>sections</em> or <em>operator sections</em>). Some examples:</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="dt">Prelude</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="cb180-2"><a href="#cb180-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span>
|
||
<span id="cb180-3"><a href="#cb180-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</span> (<span class="dv">2</span><span class="op">*</span>) [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb180-4"><a href="#cb180-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span>
|
||
<span id="cb180-5"><a href="#cb180-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</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="dv">4</span>,<span class="dv">5</span>]</span>
|
||
<span id="cb180-6"><a href="#cb180-6" aria-hidden="true" tabindex="-1"></a>[<span class="fl">1.0</span>,<span class="fl">0.5</span>,<span class="fl">0.3333333333333333</span>,<span class="fl">0.25</span>,<span class="fl">0.2</span>]</span></code></pre></div>
|
||
<h2 data-number="3.3" id="prefix-and-infix-notations"><span
|
||
class="header-section-number">3.3</span> Prefix and Infix Notations</h2>
|
||
<p>Normal Haskell functions are applied with <em>prefix notation</em>,
|
||
which is just a fancy way to say that the function name comes before the
|
||
arguments. In contrast, operators are applied with <em>infix
|
||
notation</em> – the name of the function comes between the
|
||
arguments.</p>
|
||
<p>An infix operator can be converted into a prefix function by adding
|
||
parentheses around it. For instance,</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="op">+</span>) <span class="dv">1</span> <span class="dv">2</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>This is useful especially when an operator needs to be passed as an
|
||
argument to another function.</p>
|
||
<p>As an example, the function <code>zipWith</code> takes two lists, a
|
||
binary function, and joins the lists using the function. We can use
|
||
<code>zipWith (+)</code> to sum two lists, element-by-element:</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">zipWith</span></span>
|
||
<span id="cb182-2"><a href="#cb182-2" aria-hidden="true" tabindex="-1"></a><span class="fu">zipWith</span><span class="ot"> ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> [a] <span class="ot">-></span> [b] <span class="ot">-></span> [c]</span>
|
||
<span id="cb182-3"><a href="#cb182-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">zipWith</span> (<span class="op">+</span>) [<span class="dv">0</span>,<span class="dv">2</span>,<span class="dv">5</span>] [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb182-4"><a href="#cb182-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">5</span>,<span class="dv">8</span>]</span></code></pre></div>
|
||
<p>Without the ability to turn an operator into a function, we’d have to
|
||
use a helper function – such as <code>add</code> above.</p>
|
||
<p>Note that omitting the parentheses leads into a type error:</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="dt">Prelude</span><span class="op">></span> <span class="fu">zipWith</span> <span class="op">+</span> [<span class="dv">0</span>,<span class="dv">2</span>,<span class="dv">5</span>,<span class="dv">3</span>] [<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb183-2"><a href="#cb183-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb183-3"><a href="#cb183-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">11</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb183-4"><a href="#cb183-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘[<span class="dt">Integer</span>]</span>
|
||
<span id="cb183-5"><a href="#cb183-5" aria-hidden="true" tabindex="-1"></a> <span class="ot">-></span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> [a] <span class="ot">-></span> [b] <span class="ot">-></span> [c]’</span>
|
||
<span id="cb183-6"><a href="#cb183-6" aria-hidden="true" tabindex="-1"></a> with actual <span class="kw">type</span> ‘[<span class="dt">Integer</span>]’</span>
|
||
<span id="cb183-7"><a href="#cb183-7" aria-hidden="true" tabindex="-1"></a> • <span class="dt">The</span> function ‘[<span class="dv">0</span>, <span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>]’ is applied to one argument,</span>
|
||
<span id="cb183-8"><a href="#cb183-8" aria-hidden="true" tabindex="-1"></a> but its <span class="kw">type</span> ‘[<span class="dt">Integer</span>]’ has none</span>
|
||
<span id="cb183-9"><a href="#cb183-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the second argument <span class="kw">of</span> ‘(<span class="op">+</span>)’, namely ‘[<span class="dv">0</span>, <span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>] [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">3</span>]’</span>
|
||
<span id="cb183-10"><a href="#cb183-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> <span class="fu">zipWith</span> <span class="op">+</span> [<span class="dv">0</span>, <span class="dv">2</span>, <span class="dv">5</span>, <span class="dv">3</span>] [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">3</span>]</span>
|
||
<span id="cb183-11"><a href="#cb183-11" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Relevant</span> bindings include</span>
|
||
<span id="cb183-12"><a href="#cb183-12" aria-hidden="true" tabindex="-1"></a><span class="ot"> it ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> [a] <span class="ot">-></span> [b] <span class="ot">-></span> [c]</span>
|
||
<span id="cb183-13"><a href="#cb183-13" aria-hidden="true" tabindex="-1"></a> (bound at <span class="op"><</span>interactive<span class="op">>:</span><span class="dv">1</span><span class="op">:</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<p>The reason for this weird-looking error is that GHCi got confused and
|
||
thought that we were somehow trying to add <code>zipWith</code> and
|
||
<code>[0,2,5,3] [1,3,3]</code> together. Logically, it deduced that
|
||
<code>[0,2,5,3]</code> must be a function since it’s being applied to
|
||
<code>[1,3,3]</code> (remember that functions bind tighter than
|
||
operators).</p>
|
||
<p>Unfortunately, error messages can sometimes be obscure, since the
|
||
compiler cannot always know the “real” cause of the error (which is in
|
||
this case was omitting the parentheses). Weird error messages are
|
||
frustrating, but only the programmer knows what was the original intent
|
||
behind the code.</p>
|
||
<p>Another nice feature of Haskell is the syntax for applying a binary
|
||
function as if it was an infix operator, by surrounding it with
|
||
backticks (`). For example:</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="dv">6</span> <span class="ot">`div`</span> <span class="dv">2</span> <span class="op">==></span> <span class="fu">div</span> <span class="dv">6</span> <span class="dv">2</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb184-2"><a href="#cb184-2" aria-hidden="true" tabindex="-1"></a>(<span class="op">+</span><span class="dv">1</span>) <span class="ot">`map`</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="op">+</span><span class="dv">1</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></code></pre></div>
|
||
<h2 data-number="3.4" id="lambdas"><span
|
||
class="header-section-number">3.4</span> Lambdas</h2>
|
||
<p>The last spanner we need in our functional programming toolbox is λ
|
||
(lambda). Lambda expressions are <em>anonymous functions</em>. Consider
|
||
a situation where you need a function only once, for example in an
|
||
expression like</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">let</span> big x <span class="ot">=</span> x<span class="op">></span><span class="dv">7</span> <span class="kw">in</span> <span class="fu">filter</span> big [<span class="dv">1</span>,<span class="dv">10</span>,<span class="dv">100</span>]</span></code></pre></div>
|
||
<p>A lambda expression allows us to write this directly, without
|
||
defining a name (<code>big</code>) for the helper function:</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="fu">filter</span> (\x <span class="ot">-></span> x<span class="op">></span><span class="dv">7</span>) [<span class="dv">1</span>,<span class="dv">10</span>,<span class="dv">100</span>]</span></code></pre></div>
|
||
<p>Here are some more examples in GHCi:</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="dt">Prelude</span><span class="op">></span> (\x <span class="ot">-></span> x<span class="op">*</span>x) <span class="dv">3</span></span>
|
||
<span id="cb187-2"><a href="#cb187-2" aria-hidden="true" tabindex="-1"></a><span class="dv">9</span></span>
|
||
<span id="cb187-3"><a href="#cb187-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (\x <span class="ot">-></span> <span class="fu">reverse</span> x <span class="op">==</span> x) <span class="st">"ABBA"</span></span>
|
||
<span id="cb187-4"><a href="#cb187-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb187-5"><a href="#cb187-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">filter</span> (\x <span class="ot">-></span> <span class="fu">reverse</span> x <span class="op">==</span> x) [<span class="st">"ABBA"</span>,<span class="st">"ACDC"</span>,<span class="st">"otto"</span>,<span class="st">"lothar"</span>,<span class="st">"anna"</span>]</span>
|
||
<span id="cb187-6"><a href="#cb187-6" aria-hidden="true" tabindex="-1"></a>[<span class="st">"ABBA"</span>,<span class="st">"otto"</span>,<span class="st">"anna"</span>]</span>
|
||
<span id="cb187-7"><a href="#cb187-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (\x y <span class="ot">-></span> x<span class="op">^</span><span class="dv">2</span><span class="op">+</span>y<span class="op">^</span><span class="dv">2</span>) <span class="dv">2</span> <span class="dv">3</span> <span class="co">-- multiple arguments</span></span>
|
||
<span id="cb187-8"><a href="#cb187-8" aria-hidden="true" tabindex="-1"></a><span class="dv">13</span></span></code></pre></div>
|
||
<p>The Haskell syntax for lambdas is a bit surprising. The backslash
|
||
character (<code>\</code>) stands for the greek letter lambda (λ). The
|
||
Haskell expression <code>\x -> x+1</code> is trying to mimic the
|
||
mathematical notation <em>λx. x+1</em>. Other languages use syntax like
|
||
<code>x => x+1</code> (JavaScript) or <code>lambda x: x+1</code>
|
||
(Python).</p>
|
||
<p><strong>Note!</strong> You never <em>need</em> to use a lambda
|
||
expression. You can always instead define the function normally using
|
||
<code>let</code> or <code>where</code>.</p>
|
||
<p>By the way, lambda expressions are quite powerful constructs which
|
||
have a deep theory of their own, known as <a
|
||
href="https://en.wikipedia.org/wiki/Lambda_calculus">Lambda
|
||
calculus</a>. Some even consider purely functional programming languages
|
||
such as Haskell to be typed extensions of Lambda calculus with extra
|
||
syntax.</p>
|
||
<h2 data-number="3.5" id="sidenote-the-.-and-operators"><span
|
||
class="header-section-number">3.5</span> Sidenote: The <code>.</code>
|
||
and <code>$</code> Operators</h2>
|
||
<p>The two most common operators in Haskell codebases are probably
|
||
<code>.</code> and <code>$</code>. They are useful when writing code
|
||
that uses higher-order functions. The first of these, the <code>.</code>
|
||
operator, is the <em>function composition</em> operator. Here’s its
|
||
type</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="ot">(.) ::</span> (b <span class="ot">-></span> c) <span class="ot">-></span> (a <span class="ot">-></span> b) <span class="ot">-></span> a <span class="ot">-></span> c</span></code></pre></div>
|
||
<p>And here’s what it does</p>
|
||
<pre><code>(f.g) x ==> f (g x)</code></pre>
|
||
<p>You can use function composition to build functions out of other
|
||
functions, without mentioning any arguments. For example:</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>double x <span class="ot">=</span> <span class="dv">2</span><span class="op">*</span>x</span>
|
||
<span id="cb190-2"><a href="#cb190-2" aria-hidden="true" tabindex="-1"></a>quadruple <span class="ot">=</span> double <span class="op">.</span> double <span class="co">-- computes 2*(2*x) == 4*x</span></span>
|
||
<span id="cb190-3"><a href="#cb190-3" aria-hidden="true" tabindex="-1"></a>f <span class="ot">=</span> quadruple <span class="op">.</span> (<span class="op">+</span><span class="dv">1</span>) <span class="co">-- computes 4*(x+1)</span></span>
|
||
<span id="cb190-4"><a href="#cb190-4" aria-hidden="true" tabindex="-1"></a>g <span class="ot">=</span> (<span class="op">+</span><span class="dv">1</span>) <span class="op">.</span> quadruple <span class="co">-- computes 4*x+1</span></span>
|
||
<span id="cb190-5"><a href="#cb190-5" aria-hidden="true" tabindex="-1"></a>third <span class="ot">=</span> <span class="fu">head</span> <span class="op">.</span> <span class="fu">tail</span> <span class="op">.</span> <span class="fu">tail</span> <span class="co">-- fetches the third element of a list</span></span></code></pre></div>
|
||
<p>We can also reimplement <code>doTwice</code> using <code>(.)</code>.
|
||
Note how we can use <code>doTwice</code> both as applied only to a
|
||
function, or as applied to a function and a value.</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">doTwice ::</span> (a <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb191-2"><a href="#cb191-2" aria-hidden="true" tabindex="-1"></a>doTwice f <span class="ot">=</span> f <span class="op">.</span> f</span></code></pre></div>
|
||
<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><span class="kw">let</span> ttail <span class="ot">=</span> doTwice <span class="fu">tail</span></span>
|
||
<span id="cb192-2"><a href="#cb192-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> ttail [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb192-3"><a href="#cb192-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb192-4"><a href="#cb192-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb192-5"><a href="#cb192-5" aria-hidden="true" tabindex="-1"></a>(doTwice <span class="fu">tail</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">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb192-6"><a href="#cb192-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb192-7"><a href="#cb192-7" aria-hidden="true" tabindex="-1"></a>doTwice <span class="fu">tail</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">3</span>,<span class="dv">4</span>]</span></code></pre></div>
|
||
<p>Often function composition is not used when defining a new function,
|
||
but instead to avoid defining a helper function. For instance, consider
|
||
the difference between these two expressions:</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="kw">let</span> notEmpty x <span class="ot">=</span> <span class="fu">not</span> (<span class="fu">null</span> x)</span>
|
||
<span id="cb193-2"><a href="#cb193-2" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="fu">filter</span> notEmpty [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[],[<span class="dv">4</span>]]</span>
|
||
<span id="cb193-3"><a href="#cb193-3" 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></code></pre></div>
|
||
<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="fu">filter</span> (<span class="fu">not</span> <span class="op">.</span> <span class="fu">null</span>) [[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>],[],[<span class="dv">4</span>]]</span>
|
||
<span id="cb194-2"><a href="#cb194-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">4</span>]]</span></code></pre></div>
|
||
<p>The other operator, <code>$</code> is more subtle. Let’s look at its
|
||
type.</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="ot">($) ::</span> (a <span class="ot">-></span> b) <span class="ot">-></span> a <span class="ot">-></span> b</span></code></pre></div>
|
||
<p>It takes a function of type <code>a -> b</code> and a value of
|
||
type <code>a</code>, and returns a value of type <code>b</code>. In
|
||
other words, it’s a function application operator. The expression
|
||
<code>f $ x</code> is the same as <code>f x</code>. This seems pretty
|
||
useless, but it means that the <code>$</code> operator can be used to
|
||
eliminate parentheses! These expressions are the same:</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="fu">head</span> (<span class="fu">reverse</span> <span class="st">"abcd"</span>)</span>
|
||
<span id="cb196-2"><a href="#cb196-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> <span class="op">$</span> <span class="fu">reverse</span> <span class="st">"abcd"</span></span></code></pre></div>
|
||
<p>This isn’t that impressive when it’s used to eliminate one pair of
|
||
parentheses, but together <code>.</code> and <code>$</code> can
|
||
eliminate lots of them! For example, we can rewrite</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">reverse</span> (<span class="fu">map</span> <span class="fu">head</span> (<span class="fu">map</span> <span class="fu">reverse</span> ([<span class="st">"Haskell"</span>,<span class="st">"pro"</span>] <span class="op">++</span> [<span class="st">"dodo"</span>,<span class="st">"lyric"</span>])))</span></code></pre></div>
|
||
<p>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="fu">reverse</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">head</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">reverse</span>) ([<span class="st">"Haskell"</span>,<span class="st">"pro"</span>] <span class="op">++</span> [<span class="st">"dodo"</span>,<span class="st">"lyric"</span>])</span></code></pre></div>
|
||
<p>and then</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="fu">reverse</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">head</span> <span class="op">.</span> <span class="fu">map</span> <span class="fu">reverse</span> <span class="op">$</span> [<span class="st">"Haskell"</span>,<span class="st">"pro"</span>] <span class="op">++</span> [<span class="st">"dodo"</span>,<span class="st">"lyric"</span>]</span></code></pre></div>
|
||
<p>Sometimes the operators <code>.</code> and <code>$</code> are useful
|
||
as functions in their own right. For example, a list of functions can be
|
||
applied to an argument using map and a section of <code>$</code>:</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">map</span> (<span class="op">$</span><span class="st">"string"</span>) [<span class="fu">reverse</span>, <span class="fu">take</span> <span class="dv">2</span>, <span class="fu">drop</span> <span class="dv">2</span>]</span>
|
||
<span id="cb200-2"><a href="#cb200-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="fu">reverse</span> <span class="op">$</span> <span class="st">"string"</span>, <span class="fu">take</span> <span class="dv">2</span> <span class="op">$</span> <span class="st">"string"</span>, <span class="fu">drop</span> <span class="dv">2</span> <span class="op">$</span> <span class="st">"string"</span>]</span>
|
||
<span id="cb200-3"><a href="#cb200-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="fu">reverse</span> <span class="st">"string"</span>, <span class="fu">take</span> <span class="dv">2</span> <span class="st">"string"</span>, <span class="fu">drop</span> <span class="dv">2</span> <span class="st">"string"</span>]</span>
|
||
<span id="cb200-4"><a href="#cb200-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"gnirts"</span>, <span class="st">"st"</span>, <span class="st">"ring"</span>]</span></code></pre></div>
|
||
<!-- `zipWith (.)` would be an example on using `.` as a function. -->
|
||
<p>If this seems complicated, don’t worry. You don’t need to use
|
||
<code>.</code> and <code>$</code> in your own code until you’re
|
||
comfortable with them. However, you’ll bump into <code>.</code> and
|
||
<code>$</code> when reading Haskell examples and code on the internet,
|
||
so it’s good to know about them. <a
|
||
href="https://typeclasses.com/featured/dollar">This article</a> might
|
||
also help.</p>
|
||
<h2 data-number="3.6" id="example-rewriting-whatfollows"><span
|
||
class="header-section-number">3.6</span> Example: Rewriting
|
||
<code>whatFollows</code></h2>
|
||
<p>Now, let’s rewrite the <code>whatFollows</code> example from earlier
|
||
using the tools we just saw. Here’s the original version:</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="ot">substringsOfLength ::</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="cb201-2"><a href="#cb201-2" aria-hidden="true" tabindex="-1"></a>substringsOfLength n string <span class="ot">=</span> <span class="fu">map</span> shorten (tails string)</span>
|
||
<span id="cb201-3"><a href="#cb201-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> shorten s <span class="ot">=</span> <span class="fu">take</span> n s</span>
|
||
<span id="cb201-4"><a href="#cb201-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb201-5"><a href="#cb201-5" aria-hidden="true" tabindex="-1"></a><span class="ot">whatFollows ::</span> <span class="dt">Char</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="cb201-6"><a href="#cb201-6" aria-hidden="true" tabindex="-1"></a>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> (<span class="fu">filter</span> match (substringsOfLength (k<span class="op">+</span><span class="dv">1</span>) string))</span>
|
||
<span id="cb201-7"><a href="#cb201-7" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> match sub <span class="ot">=</span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span></code></pre></div>
|
||
<p>To get started, let’s get rid of the helper function
|
||
<code>substringsOfLength</code> and move all the code to
|
||
<code>whatFollows</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>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> (<span class="fu">filter</span> match (<span class="fu">map</span> shorten (tails string)))</span>
|
||
<span id="cb202-2"><a href="#cb202-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> shorten s <span class="ot">=</span> <span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>) s</span>
|
||
<span id="cb202-3"><a href="#cb202-3" aria-hidden="true" tabindex="-1"></a> match sub <span class="ot">=</span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span></code></pre></div>
|
||
<p>Now let’s use partial application instead of defining
|
||
<code>shorten</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>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> (<span class="fu">filter</span> match (<span class="fu">map</span> (<span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>)) (tails string)))</span>
|
||
<span id="cb203-2"><a href="#cb203-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> match sub <span class="ot">=</span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span></code></pre></div>
|
||
<p>Let’s use <code>.</code> and <code>$</code> to eliminate some of
|
||
those parentheses:</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>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> <span class="op">.</span> <span class="fu">filter</span> match <span class="op">.</span> <span class="fu">map</span> (<span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>)) <span class="op">$</span> tails string</span>
|
||
<span id="cb204-2"><a href="#cb204-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> match sub <span class="ot">=</span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span></code></pre></div>
|
||
<p>We can also replace <code>match</code> with a lambda:</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>whatFollows c k string <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> <span class="op">.</span> <span class="fu">filter</span> (\sub <span class="ot">-></span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]) <span class="op">.</span> <span class="fu">map</span> (<span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>)) <span class="op">$</span> tails string</span></code></pre></div>
|
||
<p>Finally, we don’t need to mention the <code>string</code> parameter
|
||
at all, since we can just express <code>whatFollows</code> as a
|
||
composition of <code>map</code>, <code>filter</code>, <code>map</code>
|
||
and <code>tails</code>:</p>
|
||
<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>whatFollows c k <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> <span class="op">.</span> <span class="fu">filter</span> (\sub <span class="ot">-></span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]) <span class="op">.</span> <span class="fu">map</span> (<span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>)) <span class="op">.</span> tails</span></code></pre></div>
|
||
<p>We can even go a bit further by rewriting the lambda using an
|
||
operator section</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> \sub <span class="ot">-></span> <span class="fu">take</span> <span class="dv">1</span> sub <span class="op">==</span> [c]</span>
|
||
<span id="cb207-2"><a href="#cb207-2" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> \sub <span class="ot">-></span> (<span class="op">==</span>[c]) (<span class="fu">take</span> <span class="dv">1</span> sub)</span>
|
||
<span id="cb207-3"><a href="#cb207-3" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> \sub <span class="ot">-></span> (<span class="op">==</span>[c]) ((<span class="fu">take</span> <span class="dv">1</span>) sub)</span>
|
||
<span id="cb207-4"><a href="#cb207-4" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> \sub <span class="ot">-></span> ((<span class="op">==</span>[c]) <span class="op">.</span> (<span class="fu">take</span> <span class="dv">1</span>)) sub</span>
|
||
<span id="cb207-5"><a href="#cb207-5" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> ((<span class="op">==</span>[c]) <span class="op">.</span> (<span class="fu">take</span> <span class="dv">1</span>))</span>
|
||
<span id="cb207-6"><a href="#cb207-6" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> ((<span class="op">==</span>[c]) <span class="op">.</span> <span class="fu">take</span> <span class="dv">1</span>)</span></code></pre></div>
|
||
<p>Now what we have left is:</p>
|
||
<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>whatFollows c k <span class="ot">=</span> <span class="fu">map</span> <span class="fu">tail</span> <span class="op">.</span> <span class="fu">filter</span> ((<span class="op">==</span>[c]) <span class="op">.</span> <span class="fu">take</span> <span class="dv">1</span>) <span class="op">.</span> <span class="fu">map</span> (<span class="fu">take</span> (k<span class="op">+</span><span class="dv">1</span>)) <span class="op">.</span> tails</span></code></pre></div>
|
||
<p>This is a somewhat extreme version of the function, but when used in
|
||
moderation the techniques shown here can make code easier to read.</p>
|
||
<h2 data-number="3.7" id="more-functional-list-wrangling-examples"><span
|
||
class="header-section-number">3.7</span> More Functional List Wrangling
|
||
Examples</h2>
|
||
<p>Here are some more examples of functional programming with lists.
|
||
Let’s start by introducing a couple of new list functions:</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="fu">takeWhile</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 class="co">-- take elements from a list as long as they satisfy a predicate</span></span>
|
||
<span id="cb209-2"><a href="#cb209-2" aria-hidden="true" tabindex="-1"></a><span class="fu">dropWhile</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 class="co">-- drop elements from a list as long as they satisfy a predicate</span></span></code></pre></div>
|
||
<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="fu">takeWhile</span> <span class="fu">even</span> [<span class="dv">2</span>,<span class="dv">4</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">4</span>]</span>
|
||
<span id="cb210-2"><a href="#cb210-2" aria-hidden="true" tabindex="-1"></a><span class="fu">dropWhile</span> <span class="fu">even</span> [<span class="dv">2</span>,<span class="dv">4</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>There’s also the function <code>elem</code>, which can be used to
|
||
check if a list contains an element:</p>
|
||
<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="fu">elem</span> <span class="dv">3</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="dt">True</span></span>
|
||
<span id="cb211-2"><a href="#cb211-2" aria-hidden="true" tabindex="-1"></a><span class="fu">elem</span> <span class="dv">4</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="dt">False</span></span></code></pre></div>
|
||
<p>Using these, we can implement a function <code>findSubstring</code>
|
||
that finds the earliest and longest substring in a string that consist
|
||
only of the given characters.</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">findSubstring ::</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="cb212-2"><a href="#cb212-2" aria-hidden="true" tabindex="-1"></a>findSubstring chars <span class="ot">=</span> <span class="fu">takeWhile</span> (\x <span class="ot">-></span> <span class="fu">elem</span> x chars)</span>
|
||
<span id="cb212-3"><a href="#cb212-3" aria-hidden="true" tabindex="-1"></a> <span class="op">.</span> <span class="fu">dropWhile</span> (\x <span class="ot">-></span> <span class="fu">not</span> <span class="op">$</span> <span class="fu">elem</span> x chars)</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>findSubstring <span class="st">"a"</span> <span class="st">"bbaabaaaab"</span> <span class="op">==></span> <span class="st">"aa"</span></span>
|
||
<span id="cb213-2"><a href="#cb213-2" aria-hidden="true" tabindex="-1"></a>findSubstring <span class="st">"abcd"</span> <span class="st">"xxxyyyzabaaxxabcd"</span> <span class="op">==></span> <span class="st">"abaa"</span></span></code></pre></div>
|
||
<!-- `zipWith` has already been introduced in section 3.3 above. -->
|
||
<p>The function <code>zipWith</code> lets you combine two lists
|
||
element-by-element:</p>
|
||
<div class="sourceCode" id="cb214"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb214-1"><a href="#cb214-1" aria-hidden="true" tabindex="-1"></a><span class="fu">zipWith</span><span class="ot"> ::</span> (a <span class="ot">-></span> b <span class="ot">-></span> c) <span class="ot">-></span> [a] <span class="ot">-></span> [b] <span class="ot">-></span> [c]</span></code></pre></div>
|
||
<div class="sourceCode" id="cb215"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb215-1"><a href="#cb215-1" aria-hidden="true" tabindex="-1"></a><span class="fu">zipWith</span> (<span class="op">++</span>) [<span class="st">"John"</span>,<span class="st">"Mary"</span>] [<span class="st">"Smith"</span>,<span class="st">"Cooper"</span>]</span>
|
||
<span id="cb215-2"><a href="#cb215-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"JohnSmith"</span>,<span class="st">"MaryCooper"</span>]</span>
|
||
<span id="cb215-3"><a href="#cb215-3" aria-hidden="true" tabindex="-1"></a><span class="fu">zipWith</span> <span class="fu">take</span> [<span class="dv">4</span>,<span class="dv">3</span>] [<span class="st">"Hello"</span>,<span class="st">"Warden"</span>]</span>
|
||
<span id="cb215-4"><a href="#cb215-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"Hell"</span>,<span class="st">"War"</span>]</span></code></pre></div>
|
||
<p>Sometimes with higher-order functions it’s useful to have a function
|
||
that does nothing. The function <code>id :: a -> a</code> is the
|
||
identity function and just returns its argument.</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="fu">id</span> <span class="dv">3</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb216-2"><a href="#cb216-2" aria-hidden="true" tabindex="-1"></a><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 class="op">==></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p>This seems a bit useless, but you can use it for example with
|
||
<code>filter</code> or <code>dropWhile</code>:</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="fu">filter</span> <span class="fu">id</span> [<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">True</span>] <span class="op">==></span> [<span class="dt">True</span>,<span class="dt">True</span>,<span class="dt">True</span>]</span>
|
||
<span id="cb217-2"><a href="#cb217-2" aria-hidden="true" tabindex="-1"></a><span class="fu">dropWhile</span> <span class="fu">id</span> [<span class="dt">True</span>,<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>] <span class="op">==></span> [<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>]</span></code></pre></div>
|
||
<p>Another very simple but sometimes crucial function is the constant
|
||
function, <code>const :: a -> b -> a</code>. It always returns its
|
||
first argument:</p>
|
||
<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><span class="fu">const</span> <span class="dv">3</span> <span class="dt">True</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb218-2"><a href="#cb218-2" aria-hidden="true" tabindex="-1"></a><span class="fu">const</span> <span class="dv">3</span> <span class="dv">0</span> <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>When partially applied it can be used when you need a function that
|
||
always returns the same value:</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="fu">map</span> (<span class="fu">const</span> <span class="dv">5</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">5</span>,<span class="dv">5</span>,<span class="dv">5</span>,<span class="dv">5</span>]</span>
|
||
<span id="cb219-2"><a href="#cb219-2" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> (<span class="fu">const</span> <span class="dt">True</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">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span></code></pre></div>
|
||
<h2 data-number="3.8" id="lists-and-recursion"><span
|
||
class="header-section-number">3.8</span> Lists and Recursion</h2>
|
||
<p>Here’s a new operator, <code>:</code></p>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="dv">1</span><span class="op">:</span>[]</span>
|
||
<span id="cb220-2"><a href="#cb220-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>]</span>
|
||
<span id="cb220-3"><a href="#cb220-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</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="cb220-4"><a href="#cb220-4" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb220-5"><a href="#cb220-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">tail</span> (<span class="dv">1</span><span class="op">:</span>[<span class="dv">2</span>,<span class="dv">3</span>])</span>
|
||
<span id="cb220-6"><a href="#cb220-6" aria-hidden="true" tabindex="-1"></a>[<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb220-7"><a href="#cb220-7" 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="dv">3</span>])</span>
|
||
<span id="cb220-8"><a href="#cb220-8" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb220-9"><a href="#cb220-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t (<span class="op">:</span>)</span>
|
||
<span id="cb220-10"><a href="#cb220-10" aria-hidden="true" tabindex="-1"></a><span class="ot">(:) ::</span> a <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span></code></pre></div>
|
||
<p>The <code>:</code> operator builds a list out of a head and a tail.
|
||
In other words, <code>x : xs</code> is the same as
|
||
<code>[x] ++ xs</code>. Why do we need an operator for this?</p>
|
||
<p>Actually, <code>:</code> is the <em>constructor</em> for lists: it
|
||
returns a new linked list node. The other list constructor is
|
||
<code>[]</code>, the empty list. All lists are built using
|
||
<code>:</code> and <code>[]</code>. The familiar <code>[x,y,z]</code>
|
||
syntax is actually just a nicer way to write <code>x:y:z:[]</code>, or
|
||
even more explicitly, <code>x:(y:(z:[]))</code>. In fact
|
||
<code>(++)</code> is defined in terms of <code>:</code> and recursion in
|
||
the standard library.</p>
|
||
<p>Here’s a picture of how <code>[1,2,3]</code> is structured in
|
||
memory:</p>
|
||
<p><img src="img/list123.svg" /></p>
|
||
<!--
|
||
```
|
||
(:)
|
||
/ \
|
||
1 (:)
|
||
/ \
|
||
2 (:)
|
||
/ \
|
||
3 []
|
||
```
|
||
-->
|
||
<h3 data-number="3.8.1" id="building-a-list"><span
|
||
class="header-section-number">3.8.1</span> Building a List</h3>
|
||
<p>Using <code>:</code> we can define recursive functions that build
|
||
lists. For example here’s a function that builds lists like
|
||
<code>[3,2,1]</code>:</p>
|
||
<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>descend <span class="dv">0</span> <span class="ot">=</span> []</span>
|
||
<span id="cb221-2"><a href="#cb221-2" aria-hidden="true" tabindex="-1"></a>descend n <span class="ot">=</span> n <span class="op">:</span> descend (n<span class="op">-</span><span class="dv">1</span>)</span></code></pre></div>
|
||
<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>descend <span class="dv">4</span> <span class="op">==></span> [<span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">2</span>,<span class="dv">1</span>]</span></code></pre></div>
|
||
<p>Here’s a function that builds a list by iterating a function
|
||
<code>n</code> times:</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="fu">iterate</span> f <span class="dv">0</span> x <span class="ot">=</span> [x]</span>
|
||
<span id="cb223-2"><a href="#cb223-2" aria-hidden="true" tabindex="-1"></a><span class="fu">iterate</span> f n x <span class="ot">=</span> x <span class="op">:</span> <span class="fu">iterate</span> f (n<span class="op">-</span><span class="dv">1</span>) (f x)</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><span class="fu">iterate</span> (<span class="op">*</span><span class="dv">2</span>) <span class="dv">4</span> <span class="dv">3</span> <span class="op">==></span> [<span class="dv">3</span>,<span class="dv">6</span>,<span class="dv">12</span>,<span class="dv">24</span>,<span class="dv">48</span>]</span>
|
||
<span id="cb224-2"><a href="#cb224-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb224-3"><a href="#cb224-3" aria-hidden="true" tabindex="-1"></a><span class="kw">let</span> xs <span class="ot">=</span> <span class="st">"terve"</span></span>
|
||
<span id="cb224-4"><a href="#cb224-4" aria-hidden="true" tabindex="-1"></a><span class="kw">in</span> <span class="fu">iterate</span> <span class="fu">tail</span> (<span class="fu">length</span> xs) xs</span>
|
||
<span id="cb224-5"><a href="#cb224-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"terve"</span>,<span class="st">"erve"</span>,<span class="st">"rve"</span>,<span class="st">"ve"</span>,<span class="st">"e"</span>,<span class="st">""</span>]</span></code></pre></div>
|
||
<p>Here’s a more complicated example: splitting a string into pieces at
|
||
a given character:</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="ot">split ::</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="cb225-2"><a href="#cb225-2" aria-hidden="true" tabindex="-1"></a>split c [] <span class="ot">=</span> []</span>
|
||
<span id="cb225-3"><a href="#cb225-3" aria-hidden="true" tabindex="-1"></a>split c xs <span class="ot">=</span> start <span class="op">:</span> split c (<span class="fu">drop</span> <span class="dv">1</span> rest)</span>
|
||
<span id="cb225-4"><a href="#cb225-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> start <span class="ot">=</span> <span class="fu">takeWhile</span> (<span class="op">/=</span>c) xs</span>
|
||
<span id="cb225-5"><a href="#cb225-5" aria-hidden="true" tabindex="-1"></a> rest <span class="ot">=</span> <span class="fu">dropWhile</span> (<span class="op">/=</span>c) xs</span></code></pre></div>
|
||
<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>split <span class="ch">'x'</span> <span class="st">"fooxxbarxquux"</span> <span class="op">==></span> [<span class="st">"foo"</span>,<span class="st">""</span>,<span class="st">"bar"</span>,<span class="st">"quu"</span>]</span></code></pre></div>
|
||
<h3 data-number="3.8.2" id="pattern-matching-for-lists"><span
|
||
class="header-section-number">3.8.2</span> Pattern Matching for
|
||
Lists</h3>
|
||
<p>Last lecture, it was said that constructors are things that can be
|
||
pattern matched on. Above, it was divulged that the constructors for the
|
||
list type are <code>:</code> and <code>[]</code>. We can put one and one
|
||
together and guess that we can pattern match on <code>:</code> and
|
||
<code>[]</code>. This is true! Here’s how you can define your own
|
||
versions of <code>head</code> and <code>tail</code> using pattern
|
||
matching:</p>
|
||
<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">myhead ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb227-2"><a href="#cb227-2" aria-hidden="true" tabindex="-1"></a>myhead [] <span class="ot">=</span> <span class="op">-</span><span class="dv">1</span></span>
|
||
<span id="cb227-3"><a href="#cb227-3" aria-hidden="true" tabindex="-1"></a>myhead (first<span class="op">:</span>rest) <span class="ot">=</span> first</span>
|
||
<span id="cb227-4"><a href="#cb227-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb227-5"><a href="#cb227-5" aria-hidden="true" tabindex="-1"></a><span class="ot">mytail ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb227-6"><a href="#cb227-6" aria-hidden="true" tabindex="-1"></a>mytail [] <span class="ot">=</span> []</span>
|
||
<span id="cb227-7"><a href="#cb227-7" aria-hidden="true" tabindex="-1"></a>mytail (first<span class="op">:</span>rest) <span class="ot">=</span> rest</span></code></pre></div>
|
||
<p>You can <em>nest</em> patterns. That is, you can pattern match more
|
||
than one element from the start of a list. In this example, we use the
|
||
pattern <code>(a:b:_)</code> which is the same as
|
||
<code>(a:(b:_))</code>:</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="ot">sumFirstTwo ::</span> [<span class="dt">Integer</span>] <span class="ot">-></span> <span class="dt">Integer</span></span>
|
||
<span id="cb228-2"><a href="#cb228-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- this equation gets used for lists of length at least two</span></span>
|
||
<span id="cb228-3"><a href="#cb228-3" aria-hidden="true" tabindex="-1"></a>sumFirstTwo (a<span class="op">:</span>b<span class="op">:</span>_) <span class="ot">=</span> a<span class="op">+</span>b</span>
|
||
<span id="cb228-4"><a href="#cb228-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- this equation gets used for all other lists (i.e. lists of length 0 or 1)</span></span>
|
||
<span id="cb228-5"><a href="#cb228-5" aria-hidden="true" tabindex="-1"></a>sumFirstTwo _ <span class="ot">=</span> <span class="dv">0</span></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>sumFirstTwo [<span class="dv">1</span>] <span class="op">==></span> <span class="dv">0</span></span>
|
||
<span id="cb229-2"><a href="#cb229-2" aria-hidden="true" tabindex="-1"></a>sumFirstTwo [<span class="dv">1</span>,<span class="dv">2</span>] <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb229-3"><a href="#cb229-3" aria-hidden="true" tabindex="-1"></a>sumFirstTwo [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">4</span>] <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>Here’s an example that uses many different list patterns:</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">describeList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb230-2"><a href="#cb230-2" aria-hidden="true" tabindex="-1"></a>describeList [] <span class="ot">=</span> <span class="st">"an empty list"</span></span>
|
||
<span id="cb230-3"><a href="#cb230-3" aria-hidden="true" tabindex="-1"></a>describeList (x<span class="op">:</span>[]) <span class="ot">=</span> <span class="st">"a list with one element"</span></span>
|
||
<span id="cb230-4"><a href="#cb230-4" aria-hidden="true" tabindex="-1"></a>describeList (x<span class="op">:</span>y<span class="op">:</span>[]) <span class="ot">=</span> <span class="st">"a list with two elements"</span></span>
|
||
<span id="cb230-5"><a href="#cb230-5" aria-hidden="true" tabindex="-1"></a>describeList (x<span class="op">:</span>y<span class="op">:</span>z<span class="op">:</span>xs) <span class="ot">=</span> <span class="st">"a list with at least three elements"</span></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>describeList [<span class="dv">1</span>,<span class="dv">3</span>] <span class="op">==></span> <span class="st">"a list with two elements"</span></span>
|
||
<span id="cb231-2"><a href="#cb231-2" aria-hidden="true" tabindex="-1"></a>describeList [<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="op">==></span> <span class="st">"a list with at least three elements"</span></span></code></pre></div>
|
||
<p>List patterns that end with <code>:[]</code> can be typed out as list
|
||
literals. That is, just like <code>[1,2,3]</code> is the same value as
|
||
<code>1:2:3:[]</code>, the pattern <code>[x,y]</code> is the same as the
|
||
pattern <code>x:y:[]</code>. Let’s rewrite that previous example.</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="ot">describeList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb232-2"><a href="#cb232-2" aria-hidden="true" tabindex="-1"></a>describeList [] <span class="ot">=</span> <span class="st">"an empty list"</span></span>
|
||
<span id="cb232-3"><a href="#cb232-3" aria-hidden="true" tabindex="-1"></a>describeList [x] <span class="ot">=</span> <span class="st">"a list with exactly one element"</span></span>
|
||
<span id="cb232-4"><a href="#cb232-4" aria-hidden="true" tabindex="-1"></a>describeList [x,y] <span class="ot">=</span> <span class="st">"a list with exactly two elements"</span></span>
|
||
<span id="cb232-5"><a href="#cb232-5" aria-hidden="true" tabindex="-1"></a>describeList (x<span class="op">:</span>y<span class="op">:</span>z<span class="op">:</span>xs) <span class="ot">=</span> <span class="st">"a list with at least three elements"</span></span></code></pre></div>
|
||
<p>Another way we can nest patterns is pattern matching on the head
|
||
while pattern matching on a list. For example this function checks if a
|
||
list starts with <code>0</code>:</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="ot">startsWithZero ::</span> [<span class="dt">Integer</span>] <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb233-2"><a href="#cb233-2" aria-hidden="true" tabindex="-1"></a>startsWithZero (<span class="dv">0</span><span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb233-3"><a href="#cb233-3" aria-hidden="true" tabindex="-1"></a>startsWithZero (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb233-4"><a href="#cb233-4" aria-hidden="true" tabindex="-1"></a>startsWithZero [] <span class="ot">=</span> <span class="dt">False</span></span></code></pre></div>
|
||
<!-- The last two cases could be merged as `startsWithZero _ = False`. -->
|
||
<h3 data-number="3.8.3" id="consuming-a-list"><span
|
||
class="header-section-number">3.8.3</span> Consuming a List</h3>
|
||
<p>Using pattern matching and recursion, we can recursively process a
|
||
whole list. Here’s how you sum all the numbers in a list:</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="ot">sumNumbers ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb234-2"><a href="#cb234-2" aria-hidden="true" tabindex="-1"></a>sumNumbers [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb234-3"><a href="#cb234-3" aria-hidden="true" tabindex="-1"></a>sumNumbers (x<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">+</span> sumNumbers xs</span></code></pre></div>
|
||
<p>Here’s how you compute the largest number in a list, this time using
|
||
a helper function.</p>
|
||
<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><span class="ot">myMaximum ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb235-2"><a href="#cb235-2" aria-hidden="true" tabindex="-1"></a>myMaximum [] <span class="ot">=</span> <span class="dv">0</span> <span class="co">-- actually this should be some sort of error...</span></span>
|
||
<span id="cb235-3"><a href="#cb235-3" aria-hidden="true" tabindex="-1"></a>myMaximum (x<span class="op">:</span>xs) <span class="ot">=</span> go x xs</span>
|
||
<span id="cb235-4"><a href="#cb235-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go biggest [] <span class="ot">=</span> biggest</span>
|
||
<span id="cb235-5"><a href="#cb235-5" aria-hidden="true" tabindex="-1"></a> go biggest (x<span class="op">:</span>xs) <span class="ot">=</span> go (<span class="fu">max</span> biggest x) xs</span></code></pre></div>
|
||
<p><strong>Note!</strong>, “<code>go</code>” is just a cute name for the
|
||
helper function here. It’s not special syntax.</p>
|
||
<p>It’s often convenient to use nested patterns while consuming a list.
|
||
Here’s an example that counts how many <code>Nothing</code> values occur
|
||
in a list of <code>Maybe</code>s:</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">countNothings ::</span> [<span class="dt">Maybe</span> a] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb236-2"><a href="#cb236-2" aria-hidden="true" tabindex="-1"></a>countNothings [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb236-3"><a href="#cb236-3" aria-hidden="true" tabindex="-1"></a>countNothings (<span class="dt">Nothing</span> <span class="op">:</span> xs) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> countNothings xs</span>
|
||
<span id="cb236-4"><a href="#cb236-4" aria-hidden="true" tabindex="-1"></a>countNothings (<span class="dt">Just</span> _ <span class="op">:</span> xs) <span class="ot">=</span> countNothings xs</span></code></pre></div>
|
||
<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>countNothings [<span class="dt">Nothing</span>,<span class="dt">Just</span> <span class="dv">1</span>,<span class="dt">Nothing</span>] <span class="op">==></span> <span class="dv">2</span></span></code></pre></div>
|
||
<h3 data-number="3.8.4" id="building-and-consuming-a-list"><span
|
||
class="header-section-number">3.8.4</span> Building and Consuming a
|
||
List</h3>
|
||
<p>Now that we can build and consume lists, let’s do both of them at the
|
||
same time. This function doubles all elements in a list.</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="ot">doubleList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb238-2"><a href="#cb238-2" aria-hidden="true" tabindex="-1"></a>doubleList [] <span class="ot">=</span> []</span>
|
||
<span id="cb238-3"><a href="#cb238-3" aria-hidden="true" tabindex="-1"></a>doubleList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dv">2</span><span class="op">*</span>x <span class="op">:</span> doubleList xs</span></code></pre></div>
|
||
<p>It evaluates like this:</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>doubleList [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb239-2"><a href="#cb239-2" aria-hidden="true" tabindex="-1"></a><span class="op">===</span> doubleList (<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="cb239-3"><a href="#cb239-3" 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 class="op">:</span> doubleList (<span class="dv">2</span><span class="op">:</span>(<span class="dv">3</span><span class="op">:</span>[]))</span>
|
||
<span id="cb239-4"><a href="#cb239-4" 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 class="op">:</span> (<span class="dv">2</span><span class="op">*</span><span class="dv">2</span> <span class="op">:</span> doubleList (<span class="dv">3</span><span class="op">:</span>[]))</span>
|
||
<span id="cb239-5"><a href="#cb239-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 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">3</span> <span class="op">:</span> doubleList []))</span>
|
||
<span id="cb239-6"><a href="#cb239-6" 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 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">3</span> <span class="op">:</span> []))</span>
|
||
<span id="cb239-7"><a href="#cb239-7" 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 class="dv">2</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>
|
||
<span id="cb239-8"><a href="#cb239-8" aria-hidden="true" tabindex="-1"></a><span class="op">==></span> [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span></code></pre></div>
|
||
<p>Once you know pattern matching for lists, it’s straightforward to
|
||
define <code>map</code> and <code>filter</code>. Actually, let’s just
|
||
look at the GHC standard library implementations. <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/src/GHC.Base.html#map">Here’s
|
||
map</a>:</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="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="cb240-2"><a href="#cb240-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> _ [] <span class="ot">=</span> []</span>
|
||
<span id="cb240-3"><a href="#cb240-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></code></pre></div>
|
||
<p>and <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/src/GHC.List.html#filter">here’s
|
||
filter</a>:</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="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="cb241-2"><a href="#cb241-2" aria-hidden="true" tabindex="-1"></a><span class="fu">filter</span> _pred [] <span class="ot">=</span> []</span>
|
||
<span id="cb241-3"><a href="#cb241-3" 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="cb241-4"><a href="#cb241-4" 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="cb241-5"><a href="#cb241-5" 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>(<strong>Note!</strong> Naming the argument <code>_pred</code> is a
|
||
way to tell the reader of the code that this argument is unused. It
|
||
could have been just <code>_</code> as well.)</p>
|
||
<h3 data-number="3.8.5" id="tail-recursion-and-lists"><span
|
||
class="header-section-number">3.8.5</span> Tail Recursion and Lists</h3>
|
||
<p>When a recursive function evaluates to a new call to that same
|
||
function with different arguments, it is called <em>tail-recursive</em>.
|
||
(The recursive call is said to be in <em>tail position</em>.) This is
|
||
the type of recursion that corresponds to an imperative loop. We’ve
|
||
already seen many examples of tail-recursive functions, but we haven’t
|
||
really contrasted the two ways for writing the same function. This is
|
||
<code>sumNumbers</code> from earlier in this lecture:</p>
|
||
<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="co">-- Not tail recursive!</span></span>
|
||
<span id="cb242-2"><a href="#cb242-2" 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="cb242-3"><a href="#cb242-3" aria-hidden="true" tabindex="-1"></a>sumNumbers [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb242-4"><a href="#cb242-4" aria-hidden="true" tabindex="-1"></a>sumNumbers (x<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">+</span> sumNumbers xs</span></code></pre></div>
|
||
<p>In the second equation the function <code>+</code> is at the top
|
||
level, i.e. in tail position. The recursive call to
|
||
<code>sumNumbers</code> is an argument of <code>+</code>. This is
|
||
<code>sumNumbers</code> written using a tail recursive helper
|
||
function:</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="co">-- Tail recursive version</span></span>
|
||
<span id="cb243-2"><a href="#cb243-2" 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="cb243-3"><a href="#cb243-3" aria-hidden="true" tabindex="-1"></a>sumNumbers xs <span class="ot">=</span> go <span class="dv">0</span> xs</span>
|
||
<span id="cb243-4"><a href="#cb243-4" 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="cb243-5"><a href="#cb243-5" 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>Note the second equation of <code>go</code>: it has the recursive
|
||
call to <code>go</code> at the top level, i.e. in tail position. The
|
||
<code>+</code> is now in an argument to <code>go</code>.</p>
|
||
<p>For a function like <code>sumNumbers</code> that produces a single
|
||
value (a number), it doesn’t really matter which form of recursion you
|
||
choose. The non-tail-recursive function is easier to read, while the
|
||
tail-recursive one can be easier to come up with. You can try writing a
|
||
function both ways. The tail-recursive form might be more efficient, but
|
||
that depends on many details. We’ll talk more about Haskell performance
|
||
in part 2 of this course.</p>
|
||
<p>However, when you’re returning a list there is a big difference
|
||
between these two forms. Consider the function <code>doubleList</code>
|
||
from earlier. Here it is again, implemented first directly, and then via
|
||
a tail-recursive helper function.</p>
|
||
<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">-- Not tail recursive!</span></span>
|
||
<span id="cb244-2"><a href="#cb244-2" aria-hidden="true" tabindex="-1"></a><span class="ot">doubleList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb244-3"><a href="#cb244-3" aria-hidden="true" tabindex="-1"></a>doubleList [] <span class="ot">=</span> []</span>
|
||
<span id="cb244-4"><a href="#cb244-4" aria-hidden="true" tabindex="-1"></a>doubleList (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dv">2</span><span class="op">*</span>x <span class="op">:</span> doubleList xs</span></code></pre></div>
|
||
<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><span class="co">-- Tail recursive version</span></span>
|
||
<span id="cb245-2"><a href="#cb245-2" aria-hidden="true" tabindex="-1"></a><span class="ot">doubleList ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb245-3"><a href="#cb245-3" aria-hidden="true" tabindex="-1"></a>doubleList xs <span class="ot">=</span> go [] xs</span>
|
||
<span id="cb245-4"><a href="#cb245-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go result [] <span class="ot">=</span> result</span>
|
||
<span id="cb245-5"><a href="#cb245-5" aria-hidden="true" tabindex="-1"></a> go result (x<span class="op">:</span>xs) <span class="ot">=</span> go (result<span class="op">++</span>[<span class="dv">2</span><span class="op">*</span>x]) xs</span></code></pre></div>
|
||
<p>Here the direct version is much more efficient. The <code>(:)</code>
|
||
operator works in constant time, whereas the <code>(++)</code> operator
|
||
needs to walk the whole list, needing linear time. Thus the direct
|
||
version uses linear time (<em>O(n)</em>) with respect to the length of
|
||
the list, while the tail-recursive version is quadratic
|
||
(<em>O(n²)</em>)!</p>
|
||
<p>One might be tempted to fix this by using <code>(:)</code> in the
|
||
tail-recursive version, but then the list would get generated in the
|
||
reverse order. This could be fixed with an application of
|
||
<code>reverse</code>, but that would make the resulting function quite
|
||
complicated.</p>
|
||
<p>There is another reason to prefer the direct version: laziness. We’ll
|
||
get back to laziness in part 2 of the course, but for now it’s enough
|
||
for you to know that <strong>the direct way of generating a list is
|
||
simpler, more efficient and more idiomatic</strong>. You should try to
|
||
practice it in the exercises. Check out the standard library
|
||
implementations of <code>map</code> and <code>filter</code> above, even
|
||
they produce the list directly without tail recursion!</p>
|
||
<h2 data-number="3.9" id="something-fun-list-comprehensions"><span
|
||
class="header-section-number">3.9</span> Something Fun: List
|
||
Comprehensions</h2>
|
||
<p>Haskell has <em>list comprehensions</em>, a nice syntax for defining
|
||
lists that combines the power of <code>map</code> and
|
||
<code>filter</code>. You might be familiar with Python’s list
|
||
comprehensions already. Haskell’s work pretty much the same way, but
|
||
their syntax is a bit different.</p>
|
||
<p>Mapping:</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>[<span class="dv">2</span><span class="op">*</span>i <span class="op">|</span> i<span class="ot"><-</span>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]]</span>
|
||
<span id="cb246-2"><a href="#cb246-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span></code></pre></div>
|
||
<p>Filtering:</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>[i <span class="op">|</span> i <span class="ot"><-</span> [<span class="dv">1</span><span class="op">..</span><span class="dv">7</span>], <span class="fu">even</span> i]</span>
|
||
<span id="cb247-2"><a href="#cb247-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>]</span></code></pre></div>
|
||
<p>In general, these two forms are equivalent:</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 x <span class="op">|</span> x <span class="ot"><-</span> lis, p x]</span>
|
||
<span id="cb248-2"><a href="#cb248-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> f (<span class="fu">filter</span> p lis)</span></code></pre></div>
|
||
<p>List comprehensions can do even more. You can iterate over multiple
|
||
lists:</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>[ first <span class="op">++</span> <span class="st">" "</span> <span class="op">++</span> <span class="fu">last</span> <span class="op">|</span> first <span class="ot"><-</span> [<span class="st">"John"</span>, <span class="st">"Mary"</span>], <span class="fu">last</span> <span class="ot"><-</span> [<span class="st">"Smith"</span>,<span class="st">"Cooper"</span>] ]</span>
|
||
<span id="cb249-2"><a href="#cb249-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"John Smith"</span>,<span class="st">"John Cooper"</span>,<span class="st">"Mary Smith"</span>,<span class="st">"Mary Cooper"</span>]</span></code></pre></div>
|
||
<p>You can make local definitions:</p>
|
||
<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>[ reversed <span class="op">|</span> word <span class="ot"><-</span> [<span class="st">"this"</span>,<span class="st">"is"</span>,<span class="st">"a"</span>,<span class="st">"string"</span>], <span class="kw">let</span> reversed <span class="ot">=</span> <span class="fu">reverse</span> word ]</span>
|
||
<span id="cb250-2"><a href="#cb250-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="st">"siht"</span>,<span class="st">"si"</span>,<span class="st">"a"</span>,<span class="st">"gnirts"</span>]</span></code></pre></div>
|
||
<p>You can even do pattern matching in list comprehensions!</p>
|
||
<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>firstLetters string <span class="ot">=</span> [ char <span class="op">|</span> (char<span class="op">:</span>_) <span class="ot"><-</span> <span class="fu">words</span> string ]</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>firstLetters <span class="st">"Hello World!"</span></span>
|
||
<span id="cb252-2"><a href="#cb252-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="st">"HW"</span></span></code></pre></div>
|
||
<h2 data-number="3.10" id="something-fun-custom-operators"><span
|
||
class="header-section-number">3.10</span> Something Fun: Custom
|
||
Operators</h2>
|
||
<p>In Haskell an <em>operator</em> is anything built from the characters
|
||
<code>!#$%&*+./<=>?@\^|-~</code>. Operators can be defined
|
||
just like functions (note the slightly different type annotation):</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">(<+>) ::</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="cb253-2"><a href="#cb253-2" aria-hidden="true" tabindex="-1"></a>xs <span class="op"><+></span> ys <span class="ot">=</span> <span class="fu">zipWith</span> (<span class="op">+</span>) xs ys</span></code></pre></div>
|
||
<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="ot">(+++) ::</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="cb254-2"><a href="#cb254-2" aria-hidden="true" tabindex="-1"></a>a <span class="op">+++</span> b <span class="ot">=</span> a <span class="op">++</span> <span class="st">" "</span> <span class="op">++</span> b</span></code></pre></div>
|
||
<h2 data-number="3.11" id="something-useful-typed-holes"><span
|
||
class="header-section-number">3.11</span> Something Useful: Typed
|
||
Holes</h2>
|
||
<p>Sometimes when writing Haskell it can be tricky to find expressions
|
||
that have the right type. Luckily, the compiler can help you here! A
|
||
feature called <em>Typed Holes</em> lets you leave blanks in your code,
|
||
and the compiler will tell you what type the expression in the blank
|
||
should have.</p>
|
||
<p>Blanks can look like <code>_</code> or <code>_name</code>. They can
|
||
be confused with the “anything goes” pattern <code>_</code>, but the
|
||
difference is that a hole occurs on the <em>right side</em> of a
|
||
<code>=</code>, while an anything goes pattern occurs on the <em>left
|
||
side</em> of a <code>=</code>.</p>
|
||
<p>Let’s start with a simple example in GHCi:</p>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="fu">filter</span> _hole [<span class="dt">True</span>,<span class="dt">False</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="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb255-4"><a href="#cb255-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Found</span> hole<span class="op">:</span><span class="ot"> _hole ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb255-5"><a href="#cb255-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">Or</span> perhaps ‘_hole’ is mis<span class="op">-</span>spelled, <span class="fu">or</span> <span class="fu">not</span> <span class="kw">in</span> scope</span>
|
||
<span id="cb255-6"><a href="#cb255-6" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘filter’, namely ‘_hole’</span>
|
||
<span id="cb255-7"><a href="#cb255-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> <span class="fu">filter</span> _hole [<span class="dt">True</span>, <span class="dt">False</span>]</span>
|
||
<span id="cb255-8"><a href="#cb255-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> <span class="fu">filter</span> _hole [<span class="dt">True</span>, <span class="dt">False</span>]</span>
|
||
<span id="cb255-9"><a href="#cb255-9" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Relevant</span> bindings include</span>
|
||
<span id="cb255-10"><a href="#cb255-10" aria-hidden="true" tabindex="-1"></a><span class="ot"> it ::</span> [<span class="dt">Bool</span>] (bound at <span class="op"><</span>interactive<span class="op">>:</span><span class="dv">5</span><span class="op">:</span><span class="dv">1</span>)</span>
|
||
<span id="cb255-11"><a href="#cb255-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">Valid</span> hole fits include</span>
|
||
<span id="cb255-12"><a href="#cb255-12" aria-hidden="true" tabindex="-1"></a><span class="ot"> not ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb255-13"><a href="#cb255-13" aria-hidden="true" tabindex="-1"></a> (imported from ‘<span class="dt">Prelude</span>’</span>
|
||
<span id="cb255-14"><a href="#cb255-14" aria-hidden="true" tabindex="-1"></a> (<span class="fu">and</span> originally defined <span class="kw">in</span> ‘ghc<span class="op">-</span>prim<span class="op">-</span><span class="fl">0.6</span><span class="op">.</span><span class="dv">1</span><span class="op">:</span><span class="dt">GHC.Classes</span>’))</span>
|
||
<span id="cb255-15"><a href="#cb255-15" aria-hidden="true" tabindex="-1"></a><span class="ot"> id ::</span> <span class="kw">forall</span> a<span class="op">.</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb255-16"><a href="#cb255-16" aria-hidden="true" tabindex="-1"></a> with <span class="fu">id</span> <span class="op">@</span><span class="dt">Bool</span></span>
|
||
<span id="cb255-17"><a href="#cb255-17" aria-hidden="true" tabindex="-1"></a> (imported from ‘<span class="dt">Prelude</span>’ (<span class="fu">and</span> originally defined <span class="kw">in</span> ‘<span class="dt">GHC.Base</span>’))</span></code></pre></div>
|
||
<p>The important part of this message is the very first line. This tells
|
||
you what type Haskell is expecting for the hole.</p>
|
||
<pre><code><interactive>: error:
|
||
• Found hole: _hole :: Bool -> Bool</code></pre>
|
||
<p>The rest of the error message offers some suggestions for the value
|
||
of <code>_hole</code>, for example <code>id</code> and
|
||
<code>not</code>.</p>
|
||
<p>Let’s look at a longer example, where we try to implement a function
|
||
that filters a list using a list of booleans:</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>keepElements [<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>] [<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>] <span class="op">==></span> [<span class="dv">5</span>,<span class="dv">7</span>]</span></code></pre></div>
|
||
<p>We’ll start with <code>zip</code> since we know that pairs up the
|
||
elements of the two lists nicely. We add a typed hole <code>_doIt</code>
|
||
and call it with the result of <code>zip</code> to see what we need to
|
||
do next.</p>
|
||
<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><span class="ot">keepElements ::</span> [a] <span class="ot">-></span> [<span class="dt">Bool</span>] <span class="ot">-></span> [a]</span>
|
||
<span id="cb258-2"><a href="#cb258-2" aria-hidden="true" tabindex="-1"></a>keepElements xs bs <span class="ot">=</span> _doIt (<span class="fu">zip</span> xs bs)</span></code></pre></div>
|
||
<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="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb259-2"><a href="#cb259-2" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Found</span> hole<span class="op">:</span><span class="ot"> _doIt ::</span> [(a, <span class="dt">Bool</span>)] <span class="ot">-></span> [a]</span>
|
||
<span id="cb259-3"><a href="#cb259-3" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span></code></pre></div>
|
||
<p>That looks like something that could be done with <code>map</code>.
|
||
Let’s see what happens:</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="ot">keepElements ::</span> [a] <span class="ot">-></span> [<span class="dt">Bool</span>] <span class="ot">-></span> [a]</span>
|
||
<span id="cb260-2"><a href="#cb260-2" aria-hidden="true" tabindex="-1"></a>keepElements xs bs <span class="ot">=</span> <span class="fu">map</span> _f (<span class="fu">zip</span> xs bs)</span></code></pre></div>
|
||
<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="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb261-2"><a href="#cb261-2" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Found</span> hole<span class="op">:</span><span class="ot"> _f ::</span> (a, <span class="dt">Bool</span>) <span class="ot">-></span> a</span>
|
||
<span id="cb261-3"><a href="#cb261-3" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb261-4"><a href="#cb261-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Valid</span> hole fits include</span>
|
||
<span id="cb261-5"><a href="#cb261-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> fst ::</span> <span class="kw">forall</span> a b<span class="op">.</span> (a, b) <span class="ot">-></span> a</span></code></pre></div>
|
||
<p>Great! GHC reminded us of the function <code>fst</code> that grabs
|
||
the first out of a pair. Are we done now?</p>
|
||
<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><span class="ot">keepElements ::</span> [a] <span class="ot">-></span> [<span class="dt">Bool</span>] <span class="ot">-></span> [a]</span>
|
||
<span id="cb262-2"><a href="#cb262-2" aria-hidden="true" tabindex="-1"></a>keepElements xs bs <span class="ot">=</span> <span class="fu">map</span> <span class="fu">fst</span> (<span class="fu">zip</span> xs bs)</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="dt">Prelude</span><span class="op">></span> keepElements [<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>] [<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb263-2"><a href="#cb263-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>]</span></code></pre></div>
|
||
<p>Oh right, we’ve forgotten to do the filtering part. Let’s try a typed
|
||
hole again:</p>
|
||
<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><span class="ot">keepElements ::</span> [a] <span class="ot">-></span> [<span class="dt">Bool</span>] <span class="ot">-></span> [a]</span>
|
||
<span id="cb264-2"><a href="#cb264-2" aria-hidden="true" tabindex="-1"></a>keepElements xs bs <span class="ot">=</span> <span class="fu">map</span> <span class="fu">fst</span> (<span class="fu">filter</span> _predicate (<span class="fu">zip</span> xs bs))</span></code></pre></div>
|
||
<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="op"><</span>interactive<span class="op">>:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb265-2"><a href="#cb265-2" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Found</span> hole<span class="op">:</span><span class="ot"> _predicate ::</span> (a, <span class="dt">Bool</span>) <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb265-3"><a href="#cb265-3" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb265-4"><a href="#cb265-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Valid</span> hole fits include</span>
|
||
<span id="cb265-5"><a href="#cb265-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> snd ::</span> <span class="kw">forall</span> a b<span class="op">.</span> (a, b) <span class="ot">-></span> b</span>
|
||
<span id="cb265-6"><a href="#cb265-6" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb265-7"><a href="#cb265-7" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span> lots <span class="kw">of</span> other suggestions</span></code></pre></div>
|
||
<p>Again GHC has reminded us of a function that seems to do the right
|
||
thing: just grab the second element out of the tuple. Now our function
|
||
is finished and works as expected.</p>
|
||
<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><span class="ot">keepElements ::</span> [a] <span class="ot">-></span> [<span class="dt">Bool</span>] <span class="ot">-></span> [a]</span>
|
||
<span id="cb266-2"><a href="#cb266-2" aria-hidden="true" tabindex="-1"></a>keepElements xs bs <span class="ot">=</span> <span class="fu">map</span> <span class="fu">fst</span> (<span class="fu">filter</span> <span class="fu">snd</span> (<span class="fu">zip</span> xs bs))</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="dt">Prelude</span><span class="op">></span> keepElements [<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>,<span class="dv">8</span>] [<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb267-2"><a href="#cb267-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">5</span>,<span class="dv">7</span>]</span></code></pre></div>
|
||
<p><strong>Remember typed holes</strong> when you get stuck with type
|
||
errors when working on the exercises! Try replacing a function or
|
||
variable with a typed hole. It might help you figure out what you
|
||
need.</p>
|
||
<h2 data-number="3.12" id="quiz-2"><span
|
||
class="header-section-number">3.12</span> Quiz</h2>
|
||
<p>What’s the type of this function?
|
||
<code>both p q x = p x && q x</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>a -> Bool -> a -> Bool -> a -> Bool</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(a -> Bool) -> (a -> Bool) -> a -> Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>(a -> Bool) -> (b -> Bool) -> c -> Bool</code>
|
||
</li>
|
||
</ol>
|
||
<p>What’s the (most general) type of this function?
|
||
<code>applyInOut f g x = f (g (f x))</code></p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>(a -> b) -> (b -> a) -> a -> b</code>
|
||
</li>
|
||
<li>
|
||
<code>(a -> b) -> (b -> c) -> a -> c</code>
|
||
</li>
|
||
<li>
|
||
<code>(a -> a) -> (a -> a) -> a -> a</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which one of the following functions adds its first argument to the
|
||
second?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>f x x = x + x</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>f x = \y -> x + y</code>
|
||
</li>
|
||
<li>
|
||
<code>f = \x y -> x + x</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which one of the following functions does not satisfy
|
||
<code>f 1 ==> 1</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>f x = (\y -> y) x</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>f x = \y -> y</code>
|
||
</li>
|
||
<li>
|
||
<code>f x = (\y -> x) x</code>
|
||
</li>
|
||
</ol>
|
||
<p>Which one of the following functions is correctly typed?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>f x y = not x; f :: (Bool -> Bool) -> Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>f x = x ++ "a"; f :: Char -> String</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>f x = 'a' : x; f :: String -> String</code>
|
||
</li>
|
||
</ol>
|
||
<p>How many arguments does <code>drop 2</code> take?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
Zero
|
||
</li>
|
||
<li class="correct">
|
||
One
|
||
</li>
|
||
<li>
|
||
Two
|
||
</li>
|
||
</ol>
|
||
<p>What does this function do? <code>f (_:x:_) = x</code></p>
|
||
<ol class="quiz">
|
||
<li>
|
||
Returns the first element of a list
|
||
</li>
|
||
<li>
|
||
Returns an arbitrary element of a list
|
||
</li>
|
||
<li>
|
||
Returns all except the first and last elements of a list
|
||
</li>
|
||
<li class="correct">
|
||
Returns the second element of a list
|
||
</li>
|
||
</ol>
|
||
<p>What is the result of
|
||
<code>reverse $ take 5 . tail $ "This is a test"</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>"i sih"</code>
|
||
</li>
|
||
<li>
|
||
<code>"set a"</code>
|
||
</li>
|
||
<li>
|
||
A type error
|
||
</li>
|
||
</ol>
|
||
<p>If <code>f :: a -> b</code>, then what is the type of
|
||
<code>map (.f)</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>[b -> c] -> [a -> c]</code>
|
||
</li>
|
||
<li>
|
||
<code>[c -> a] -> [c -> b]</code>
|
||
</li>
|
||
<li>
|
||
<code>(b -> c) -> [a -> c]</code>
|
||
</li>
|
||
<li>
|
||
<code>[a] -> [b]</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of the leftmost <code>id</code> in
|
||
<code>id id</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
unspecified
|
||
</li>
|
||
<li>
|
||
<code>a</code></a>
|
||
<li>
|
||
<code>a -> a</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(a -> a) -> (a -> a)</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>const const</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
unspecified
|
||
</li>
|
||
<li>
|
||
<code>(c -> a -> b) -> a</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>c -> (a -> b -> a)</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> b -> c -> a</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="3.13" id="exercises-2"><span
|
||
class="header-section-number">3.13</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set3a.hs">Set3a</a>:
|
||
normal list exercises</li>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set3b.hs">Set3b</a>:
|
||
list recursion exercises</li>
|
||
</ul>
|
||
<h3 data-number="3.13.1" id="common-errors"><span
|
||
class="header-section-number">3.13.1</span> Common Errors</h3>
|
||
<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><span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Eq</span> a) arising from a use <span class="kw">of</span> ‘<span class="op">==</span>’</span></code></pre></div>
|
||
<p>You’ve probably tried to use <code>x==Nothing</code> to check if a
|
||
value is <code>Nothing</code>. Use pattern matching instead. The reason
|
||
for this error is that values of type <code>Maybe a</code> can’t be
|
||
compared because Haskell doesn’t know how to compare values of the
|
||
polymorphic type <code>a</code>. You’ll find more about this in the next
|
||
lecture. Use pattern matching instead of <code>==</code> for now.</p>
|
||
<h1 data-number="4" id="lecture-4-real-classy"><span
|
||
class="header-section-number">4</span> Lecture 4: Real Classy</h1>
|
||
<ul>
|
||
<li>Tuples</li>
|
||
<li>Type classes</li>
|
||
<li>Data structures: Map, Array</li>
|
||
</ul>
|
||
<h2 data-number="4.1" id="sidenote-tuples"><span
|
||
class="header-section-number">4.1</span> Sidenote: Tuples</h2>
|
||
<p>Before we dive into type classes, let’s introduce the last remaining
|
||
built-in datatype in Haskell: the tuple. <em>Tuples</em> or
|
||
<em>pairs</em> (or triples, quadruples, etc) are a way of bundling a
|
||
couple of values of different types together. You can think of tuples as
|
||
fixed-length lists (just like Python’s tuples). Unlike lists, each
|
||
element in the tuple can have a different type. The types of the
|
||
elements are reflected in the type of the tuple. Here are some examples
|
||
of tuple types and values:</p>
|
||
<table>
|
||
<thead>
|
||
<tr class="header">
|
||
<th style="text-align: left;">Type</th>
|
||
<th style="text-align: left;">Example value</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>(String,String)</code></td>
|
||
<td style="text-align: left;"><code>("Hello","World!")</code></td>
|
||
</tr>
|
||
<tr class="even">
|
||
<td style="text-align: left;"><code>(Int,Bool)</code></td>
|
||
<td style="text-align: left;"><code>(1,True)</code></td>
|
||
</tr>
|
||
<tr class="odd">
|
||
<td style="text-align: left;"><code>(Int,Int,Int)</code></td>
|
||
<td style="text-align: left;"><code>(4,0,3)</code></td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
<p>To get values out of tuples, you can use the functions
|
||
<code>fst</code> and <code>snd</code>:</p>
|
||
<div class="sourceCode" id="cb269"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb269-1"><a href="#cb269-1" 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="cb269-2"><a href="#cb269-2" aria-hidden="true" tabindex="-1"></a><span class="fu">snd</span><span class="ot"> ::</span> (a, b) <span class="ot">-></span> b</span></code></pre></div>
|
||
<p>You can also pattern match on tuples. This is often the most
|
||
convenient way, and also works for tuples of larger sizes. The
|
||
<code>fst</code> and <code>snd</code> functions work only on pairs.</p>
|
||
<p>Tuples are very useful in combination with lists. Here are some
|
||
examples using the <code>zip</code>, <code>unzip</code> and
|
||
<code>partition</code> functions from the <code>Data.List</code>
|
||
module.</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="fu">zip</span><span class="ot"> ::</span> [a] <span class="ot">-></span> [b] <span class="ot">-></span> [(a, b)] <span class="co">-- two lists to list of pairs</span></span>
|
||
<span id="cb270-2"><a href="#cb270-2" aria-hidden="true" tabindex="-1"></a><span class="fu">unzip</span><span class="ot"> ::</span> [(a, b)] <span class="ot">-></span> ([a], [b]) <span class="co">-- list of pairs to pair of lists</span></span>
|
||
<span id="cb270-3"><a href="#cb270-3" aria-hidden="true" tabindex="-1"></a><span class="ot">partition ::</span> (a <span class="ot">-></span> <span class="dt">Bool</span>) <span class="ot">-></span> [a] <span class="ot">-></span> ([a], [a]) <span class="co">-- elements that satisfy and don't satisfy a predicate</span></span></code></pre></div>
|
||
<!-- How about `zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]`? -->
|
||
<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">zip</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>] [<span class="dt">True</span>,<span class="dt">False</span>,<span class="dt">True</span>]</span>
|
||
<span id="cb271-2"><a href="#cb271-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [(<span class="dv">1</span>,<span class="dt">True</span>),(<span class="dv">2</span>,<span class="dt">False</span>),(<span class="dv">3</span>,<span class="dt">True</span>)]</span>
|
||
<span id="cb271-3"><a href="#cb271-3" aria-hidden="true" tabindex="-1"></a><span class="fu">unzip</span> [(<span class="st">"Fred"</span>,<span class="dv">1</span>), (<span class="st">"Jack"</span>,<span class="dv">10</span>), (<span class="st">"Helen"</span>,<span class="dv">13</span>)]</span>
|
||
<span id="cb271-4"><a href="#cb271-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> ([<span class="st">"Fred"</span>,<span class="st">"Jack"</span>,<span class="st">"Helen"</span>],[<span class="dv">1</span>,<span class="dv">10</span>,<span class="dv">13</span>])</span>
|
||
<span id="cb271-5"><a href="#cb271-5" aria-hidden="true" tabindex="-1"></a>partition (<span class="op">></span><span class="dv">0</span>) [<span class="op">-</span><span class="dv">1</span>,<span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">3</span>,<span class="dv">2</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb271-6"><a href="#cb271-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> ([<span class="dv">1</span>,<span class="dv">3</span>,<span class="dv">2</span>],[<span class="op">-</span><span class="dv">1</span>,<span class="op">-</span><span class="dv">4</span>,<span class="dv">0</span>])</span></code></pre></div>
|
||
<p>Here’s an example of pattern matching on tuples:</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">swap ::</span> (a,b) <span class="ot">-></span> (b,a)</span>
|
||
<span id="cb272-2"><a href="#cb272-2" aria-hidden="true" tabindex="-1"></a>swap (x,y) <span class="ot">=</span> (y,x)</span></code></pre></div>
|
||
<p>Here’s an example of pattern matching on tuples and lists at the same
|
||
time:</p>
|
||
<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><span class="co">-- sum all numbers that are paired with True</span></span>
|
||
<span id="cb273-2"><a href="#cb273-2" aria-hidden="true" tabindex="-1"></a><span class="ot">sumIf ::</span> [(<span class="dt">Bool</span>,<span class="dt">Int</span>)] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb273-3"><a href="#cb273-3" aria-hidden="true" tabindex="-1"></a>sumIf [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb273-4"><a href="#cb273-4" aria-hidden="true" tabindex="-1"></a>sumIf ((<span class="dt">True</span>,x)<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">+</span> sumIf xs</span>
|
||
<span id="cb273-5"><a href="#cb273-5" aria-hidden="true" tabindex="-1"></a>sumIf ((<span class="dt">False</span>,_)<span class="op">:</span>xs) <span class="ot">=</span> sumIf xs</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>sumIf [(<span class="dt">True</span>,<span class="dv">1</span>),(<span class="dt">False</span>,<span class="dv">10</span>),(<span class="dt">True</span>,<span class="dv">100</span>)]</span>
|
||
<span id="cb274-2"><a href="#cb274-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">101</span></span></code></pre></div>
|
||
<h2 data-number="4.2" id="interlude-folding"><span
|
||
class="header-section-number">4.2</span> Interlude: Folding</h2>
|
||
<!-- TODO: should this be in the same section as foldable? -->
|
||
<p>Consider the functions <code>sumNumbers :: [Int] -> Int</code>,
|
||
<code>myMaximum :: [Int] -> Int</code>, and
|
||
<code>countNothings :: [Maybe a] -> Int</code> again.</p>
|
||
<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><span class="ot">sumNumbers ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb275-2"><a href="#cb275-2" aria-hidden="true" tabindex="-1"></a>sumNumbers [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb275-3"><a href="#cb275-3" aria-hidden="true" tabindex="-1"></a>sumNumbers (x<span class="op">:</span>xs) <span class="ot">=</span> x <span class="op">+</span> sumNumbers xs</span>
|
||
<span id="cb275-4"><a href="#cb275-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb275-5"><a href="#cb275-5" aria-hidden="true" tabindex="-1"></a><span class="ot">myMaximum ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb275-6"><a href="#cb275-6" aria-hidden="true" tabindex="-1"></a>myMaximum [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb275-7"><a href="#cb275-7" aria-hidden="true" tabindex="-1"></a>myMaximum (x<span class="op">:</span>xs) <span class="ot">=</span> go x xs</span>
|
||
<span id="cb275-8"><a href="#cb275-8" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go biggest [] <span class="ot">=</span> biggest</span>
|
||
<span id="cb275-9"><a href="#cb275-9" aria-hidden="true" tabindex="-1"></a> go biggest (x<span class="op">:</span>xs) <span class="ot">=</span> go (<span class="fu">max</span> biggest x) xs</span>
|
||
<span id="cb275-10"><a href="#cb275-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb275-11"><a href="#cb275-11" aria-hidden="true" tabindex="-1"></a><span class="ot">countNothings ::</span> [<span class="dt">Maybe</span> a] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb275-12"><a href="#cb275-12" aria-hidden="true" tabindex="-1"></a>countNothings [] <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb275-13"><a href="#cb275-13" aria-hidden="true" tabindex="-1"></a>countNothings (<span class="dt">Nothing</span> <span class="op">:</span> xs) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> countNothings xs</span>
|
||
<span id="cb275-14"><a href="#cb275-14" aria-hidden="true" tabindex="-1"></a>countNothings (<span class="dt">Just</span> _ <span class="op">:</span> xs) <span class="ot">=</span> countNothings xs</span></code></pre></div>
|
||
<p>They have one common characteristic. They take a list and produce a
|
||
value that depends on the values of the elements in the given list. They
|
||
“crunch” or <em>fold</em> a list of many values into a single value.</p>
|
||
<p>Prelude has a function called <code>foldr</code>, which performs a
|
||
<em>right associative fold</em> over a <code>Foldable</code> data type.
|
||
We’ll learn more about <code>Foldable</code> soon. At this point, it
|
||
suffices to think of lists, so we define</p>
|
||
<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="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="cb276-2"><a href="#cb276-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> f y [] <span class="ot">=</span> y</span>
|
||
<span id="cb276-3"><a href="#cb276-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>What this definition says, is that for an empty list
|
||
<code>[] :: [a]</code>, <code>foldr</code> returns the default value
|
||
<code>y :: b</code>. For any other list <code>x : xs</code>,
|
||
<code>foldr</code> applies <code>f</code> to <code>x</code> and the
|
||
result of <code>foldr f y xs</code> (i.e. folding over the rest of the
|
||
list). It’s a simple definition by recursion.</p>
|
||
<p>In other words, <code>foldr</code> calls its argument function
|
||
<code>f</code> repeatedly with two arguments.</p>
|
||
<ul>
|
||
<li>The first argument is the current element from the list.</li>
|
||
<li>The second argument is what <code>f</code> returned for the rest of
|
||
the list.</li>
|
||
</ul>
|
||
<p>Consider the list <code>[1,2,3]</code>:</p>
|
||
<p><img src="img/list123.svg" /></p>
|
||
<!--
|
||
```
|
||
(:)
|
||
/ \
|
||
1 (:)
|
||
/ \
|
||
2 (:)
|
||
/ \
|
||
3 []
|
||
```
|
||
-->
|
||
<p>The expression <code>foldr (+) 0 [1,2,3]</code> evaluates as
|
||
follows:</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="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="fu">foldr</span> (<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="op">:</span><span class="dv">3</span><span class="op">:</span>[])</span>
|
||
<span id="cb277-2"><a href="#cb277-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="op">:</span><span class="dv">3</span><span class="op">:</span>[]))</span>
|
||
<span id="cb277-3"><a href="#cb277-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 class="op">:</span>[])))</span>
|
||
<span id="cb277-4"><a href="#cb277-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="cb277-5"><a href="#cb277-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></code></pre></div>
|
||
<p>The result can be thought of as a tree:</p>
|
||
<p><img src="img/sum123.svg" /></p>
|
||
<!--
|
||
```
|
||
(+)
|
||
/ \
|
||
1 (+)
|
||
/ \
|
||
2 (+)
|
||
/ \
|
||
3 0
|
||
```
|
||
-->
|
||
<p>One way to think about <code>foldr f y xs</code> is that it replaces
|
||
the <code>(:)</code> operation with <code>f</code> and <code>[]</code>
|
||
with <code>y</code>. In this case, <code>f</code> was <code>(+)</code>
|
||
and <code>y</code> was <code>0</code>. If you write out how
|
||
<code>sumNumbers [1,2,3]</code> behaves, you’ll notice that it performs
|
||
the same computation as <code>foldr (+) 0 [1,2,3]</code> does! More
|
||
generally:</p>
|
||
<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>sumNumbers xs <span class="op">==</span> <span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> xs</span></code></pre></div>
|
||
<p>Those more experienced with math may notice that we can prove this
|
||
claim by <em>induction</em>: Firstly,
|
||
<code>sumNumbers [] ==> 0</code> and
|
||
<code>foldr (+) 0 [] ==> 0</code>, so in the base case
|
||
<code>sumNumbers [] == foldr (+) 0 []</code>. Next, we may assume as our
|
||
induction hypothesis that <code>sumNumbers xs == foldr (+) 0 xs</code>
|
||
for any list <code>xs</code>. Then, for the list <code>x:xs</code>, we
|
||
have <code>sumNumbers (x:xs) ==> x + sumNumbers xs</code>. Hence,
|
||
<code>foldr (+) 0 (x:xs) ==> x + foldr (+) 0 xs ==> x + sumNumbers xs</code>
|
||
by induction hypothesis. Therefore, by induction, the equation
|
||
holds.</p>
|
||
<p>You don’t need to read, write, or understand induction proofs in this
|
||
course, but perhaps it is reassuring to know that properties and
|
||
equalities of functions in Haskell can be (in principle) analysed
|
||
mathematically, because Haskell is such a nice language. (Equalities and
|
||
properties can be analysed in any programming language, but for Haskell,
|
||
this analysis is especially convenient because Haskell is pure.)</p>
|
||
<p>Another folding example is the <code>map</code> 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><span class="fu">map</span> g xs <span class="ot">=</span> <span class="fu">foldr</span> helper [] xs</span>
|
||
<span id="cb279-2"><a href="#cb279-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> helper y ys <span class="ot">=</span> g y <span class="op">:</span> ys</span></code></pre></div>
|
||
<p>To see why this works, consider what
|
||
<code>foldr helper [] [x1,x2,..,xn]</code> does:</p>
|
||
<p><img src="img/foldr1.svg" /></p>
|
||
<!-- Do these lists actually need to be finite? -->
|
||
<!--
|
||
```
|
||
(:) helper
|
||
/ \ / \
|
||
x1 (:) x1 helper
|
||
/ \ / \
|
||
x2 (:) x2 helper
|
||
/ \ ==> / \
|
||
x3 ... x3 ...
|
||
\ \
|
||
(:) helper
|
||
/ \ / \
|
||
xn [] xn y
|
||
```
|
||
-->
|
||
<p>Now, since <code>helper x xs ==> g x : xs</code> for every
|
||
<code>x</code> and <code>xs</code>, we get that:</p>
|
||
<p><img src="img/foldr2.svg" /></p>
|
||
<!--
|
||
```
|
||
helper (:)
|
||
/ \ / \
|
||
x1 helper g x1 (:)
|
||
/ \ / \
|
||
x2 helper g x2 (:)
|
||
/ \ ==> / \
|
||
x3 ... g x3 ...
|
||
\ \
|
||
helper (:)
|
||
/ \ / \
|
||
xn y g xn y
|
||
```
|
||
-->
|
||
<p>The resulting list, <code>[ g x1, g x2, g x3, ..., g xn ]</code>, is
|
||
then exactly what we would have gotten with <code>map g xs</code>. (This
|
||
could have been also proved by induction as we did for
|
||
<code>sumNumbers</code>.) The lesson to take away is that folding is a
|
||
particular, yet quite general, way to apply some transformation
|
||
recursively into some structure (e.g. a list).</p>
|
||
<h2 data-number="4.3" id="type-classes"><span
|
||
class="header-section-number">4.3</span> Type Classes</h2>
|
||
<p>How can Haskell’s <code>+</code> work on both <code>Int</code>s and
|
||
<code>Double</code>s? Why can I compare all sorts of things with
|
||
<code>==</code>? We’ve briefly mentioned constrained types earlier.
|
||
Let’s see what they really mean. Let’s look at the types of
|
||
<code>==</code> and <code>+</code>.</p>
|
||
<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="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></code></pre></div>
|
||
<p>The type <code>(Eq a) => a -> a -> Bool</code> means:
|
||
<em>for all types <code>a</code> that belong to the class
|
||
<code>Eq</code>, this is a function of type
|
||
<code>a -> a -> Bool</code></em>. That is, if the type
|
||
<code>a</code> is a member of the class <code>Eq</code>, you can give
|
||
two values of type <code>a</code> to <code>==</code> and get a
|
||
<code>Bool</code> result.</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">(+) ::</span> (<span class="dt">Num</span> a) <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<p>Similarly, the type <code>(Num a) => a -> a -> a</code>
|
||
means: <em>for all types <code>a</code> that belong to the class
|
||
<code>Num</code>, this is a function of type
|
||
<code>a -> a -> a</code></em>. That is, you can give two values of
|
||
the same type <code>a</code> to <code>+</code> and get out a third value
|
||
of type <code>a</code>, as long as <code>a</code> is a member of
|
||
<code>Num</code>.</p>
|
||
<p><code>Num</code> and <code>Eq</code> are type classes. A <em>type
|
||
class</em> is a way to group together types that support similar
|
||
operations.</p>
|
||
<p><strong>Note!</strong> A type class is a collection of types. It
|
||
doesn’t have much to do with the classes of object oriented programming!
|
||
In some situations, type classes can act like <em>interfaces</em> in
|
||
object oriented programming. Unfortunately the functions in a type class
|
||
are often called <em>methods</em>, adding to the confusion.</p>
|
||
<p>PS. remember how using type variables for polymorphism was called
|
||
<em>parametric polymorphism</em>? The fancy word for what type classes
|
||
achieve is <em>ad-hoc polymorphism</em>. The difference is that with
|
||
parametric polymorphism the function (e.g. <code>head</code>) has the
|
||
same implementation for all types, whereas with ad-hoc polymorphisms
|
||
there are multiple implementations (consider <code>==</code> on numbers
|
||
and strings).</p>
|
||
<h2 data-number="4.4" id="type-constraints"><span
|
||
class="header-section-number">4.4</span> Type Constraints</h2>
|
||
<p>When you’re working with a concrete type (not a type variable), you
|
||
can just use type class functions (in this case, <code>(==)</code>):</p>
|
||
<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><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">Bool</span></span>
|
||
<span id="cb282-2"><a href="#cb282-2" aria-hidden="true" tabindex="-1"></a>f g x <span class="ot">=</span> x <span class="op">==</span> g x</span></code></pre></div>
|
||
<p>Of course, if the type in question isn’t a member of the right class,
|
||
you get an error. For example:</p>
|
||
<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">addTrue ::</span> <span class="dt">Bool</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb283-2"><a href="#cb283-2" aria-hidden="true" tabindex="-1"></a>addTrue b <span class="ot">=</span> b <span class="op">+</span> <span class="dt">True</span></span></code></pre></div>
|
||
<pre><code>error:
|
||
• No instance for (Num Bool) arising from a use of ‘+’
|
||
• In the expression: b + True
|
||
In an equation for ‘addTrue’: addTrue b = b + True</code></pre>
|
||
<p>However in a <em>polymorphic</em> function, you need to add <em>type
|
||
constraints</em>. This doesn’t work:</p>
|
||
<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">f ::</span> (a <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb285-2"><a href="#cb285-2" aria-hidden="true" tabindex="-1"></a>f g x <span class="ot">=</span> x <span class="op">==</span> g x</span></code></pre></div>
|
||
<p>Luckily the error is nice:</p>
|
||
<pre><code>error:
|
||
• No instance for (Eq a) arising from a use of ‘==’
|
||
Possible fix:
|
||
add (Eq a) to the context of
|
||
the type signature for:
|
||
f :: (a -> a) -> a -> Bool
|
||
• In the expression: x == g x
|
||
In an equation for ‘f’: f g x = x == g x</code></pre>
|
||
<p>To signal that <code>f</code> only works on types that are members of
|
||
the <code>Eq</code> class, we add a type constraint
|
||
<code>(Eq a) =></code> to the type annotation.</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">f ::</span> (<span class="dt">Eq</span> a) <span class="ot">=></span> (a <span class="ot">-></span> a) <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb287-2"><a href="#cb287-2" aria-hidden="true" tabindex="-1"></a>f g x <span class="ot">=</span> x <span class="op">==</span> g x</span></code></pre></div>
|
||
<p>If you don’t have a type annotation, <em>type inference</em> can
|
||
provide the constraints!</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><span class="dt">Prelude</span><span class="op">></span> f g x <span class="ot">=</span> x <span class="op">==</span> g x</span>
|
||
<span id="cb288-2"><a href="#cb288-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span><span class="kw">type</span> f</span>
|
||
<span id="cb288-3"><a href="#cb288-3" aria-hidden="true" tabindex="-1"></a><span class="ot">f ::</span> (<span class="dt">Eq</span> a) <span class="ot">=></span> (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>You can also have multiple constraints:</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="ot">bothPairsEqual ::</span> (<span class="dt">Eq</span> a, <span class="dt">Eq</span> b) <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> b <span class="ot">-></span> b <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb289-2"><a href="#cb289-2" aria-hidden="true" tabindex="-1"></a>bothPairsEqual left1 left2 right1 right2 <span class="ot">=</span> left1 <span class="op">==</span> left2 <span class="op">&&</span> right1 <span class="op">==</span> right2</span></code></pre></div>
|
||
<h2 data-number="4.5" id="standard-type-classes"><span
|
||
class="header-section-number">4.5</span> Standard Type Classes</h2>
|
||
<p>Here are some standard Haskell type classes you should know
|
||
about.</p>
|
||
<h3 data-number="4.5.1" id="eq"><span
|
||
class="header-section-number">4.5.1</span> <code>Eq</code></h3>
|
||
<p>We already saw the <code>Eq</code> class for equality comparisons.
|
||
Here are the basic operations of the <code>Eq</code> class and some
|
||
examples of their use. As you can see pretty much all the types we’ve
|
||
seen so far, except for functions, are members of <code>Eq</code>.</p>
|
||
<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="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="cb290-2"><a href="#cb290-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></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="dv">1</span> <span class="op">==</span> <span class="dv">2</span></span>
|
||
<span id="cb291-2"><a href="#cb291-2" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb291-3"><a href="#cb291-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dv">1</span> <span class="op">/=</span> <span class="dv">2</span></span>
|
||
<span id="cb291-4"><a href="#cb291-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb291-5"><a href="#cb291-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="st">"Foo"</span> <span class="op">==</span> <span class="st">"Bar"</span></span>
|
||
<span id="cb291-6"><a href="#cb291-6" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb291-7"><a href="#cb291-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</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">1</span>,<span class="dv">2</span>],[<span class="dv">3</span>,<span class="dv">4</span>]]</span>
|
||
<span id="cb291-8"><a href="#cb291-8" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb291-9"><a href="#cb291-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (\x <span class="ot">-></span> x<span class="op">+</span><span class="dv">1</span>) <span class="op">==</span> (\x <span class="ot">-></span> x<span class="op">+</span><span class="dv">2</span>)</span>
|
||
<span id="cb291-10"><a href="#cb291-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb291-11"><a href="#cb291-11" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">5</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="cb291-12"><a href="#cb291-12" aria-hidden="true" tabindex="-1"></a> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Eq</span> (<span class="dt">Integer</span> <span class="ot">-></span> <span class="dt">Integer</span>))</span>
|
||
<span id="cb291-13"><a href="#cb291-13" aria-hidden="true" tabindex="-1"></a> arising from a use <span class="kw">of</span> ‘<span class="op">==</span>’</span>
|
||
<span id="cb291-14"><a href="#cb291-14" aria-hidden="true" tabindex="-1"></a> (<span class="fu">maybe</span> you haven't applied a function to enough arguments<span class="op">?</span>)</span>
|
||
<span id="cb291-15"><a href="#cb291-15" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the expression<span class="op">:</span> (\ x <span class="ot">-></span> x <span class="op">+</span> <span class="dv">1</span>) <span class="op">==</span> (\ x <span class="ot">-></span> x <span class="op">+</span> <span class="dv">2</span>)</span>
|
||
<span id="cb291-16"><a href="#cb291-16" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> (\ x <span class="ot">-></span> x <span class="op">+</span> <span class="dv">1</span>) <span class="op">==</span> (\ x <span class="ot">-></span> x <span class="op">+</span> <span class="dv">2</span>)</span></code></pre></div>
|
||
<p>There are some other useful functions that use the <code>Eq</code>
|
||
class, like <code>nub</code> from the module <code>Data.List</code>.</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="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Data.List</span></span>
|
||
<span id="cb292-2"><a href="#cb292-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="op">></span> <span class="op">:</span>t nub</span>
|
||
<span id="cb292-3"><a href="#cb292-3" aria-hidden="true" tabindex="-1"></a><span class="ot">nub ::</span> <span class="dt">Eq</span> a <span class="ot">=></span> [a] <span class="ot">-></span> [a]</span>
|
||
<span id="cb292-4"><a href="#cb292-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="op">></span> nub [<span class="dv">3</span>,<span class="dv">5</span>,<span class="dv">3</span>,<span class="dv">1</span>,<span class="dv">1</span>] <span class="co">-- eliminates duplicates</span></span>
|
||
<span id="cb292-5"><a href="#cb292-5" aria-hidden="true" tabindex="-1"></a>[<span class="dv">3</span>,<span class="dv">5</span>,<span class="dv">1</span>]</span></code></pre></div>
|
||
<h3 data-number="4.5.2" id="ord"><span
|
||
class="header-section-number">4.5.2</span> <code>Ord</code></h3>
|
||
<p>The <code>Ord</code> class is for ordering (less than, greater than).
|
||
Again, here are the basic operations and some examples of their use.
|
||
Note the new <code>Ordering</code> type. It has values <code>LT</code>
|
||
for “less than”, <code>EQ</code> for “equal” and <code>GT</code> for
|
||
“greater than”.</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="fu">compare</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Ordering</span></span>
|
||
<span id="cb293-2"><a href="#cb293-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(<) ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb293-3"><a href="#cb293-3" aria-hidden="true" tabindex="-1"></a><span class="ot">(>) ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb293-4"><a href="#cb293-4" aria-hidden="true" tabindex="-1"></a><span class="ot">(>=) ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb293-5"><a href="#cb293-5" aria-hidden="true" tabindex="-1"></a><span class="ot">(<=) ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb293-6"><a href="#cb293-6" aria-hidden="true" tabindex="-1"></a><span class="fu">max</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb293-7"><a href="#cb293-7" aria-hidden="true" tabindex="-1"></a><span class="fu">min</span><span class="ot"> ::</span> <span class="dt">Ord</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="fu">compare</span> <span class="dv">1</span> <span class="dv">1</span> <span class="co">-- 1 is EQual to 1</span></span>
|
||
<span id="cb294-2"><a href="#cb294-2" aria-hidden="true" tabindex="-1"></a><span class="dt">EQ</span></span>
|
||
<span id="cb294-3"><a href="#cb294-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">compare</span> <span class="dv">1</span> <span class="dv">3</span> <span class="co">-- 1 is Less Than 3</span></span>
|
||
<span id="cb294-4"><a href="#cb294-4" aria-hidden="true" tabindex="-1"></a><span class="dt">LT</span></span>
|
||
<span id="cb294-5"><a href="#cb294-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">compare</span> <span class="dv">1</span> <span class="dv">0</span> <span class="co">-- 1 is Greater Than 0</span></span>
|
||
<span id="cb294-6"><a href="#cb294-6" aria-hidden="true" tabindex="-1"></a><span class="dt">GT</span></span>
|
||
<span id="cb294-7"><a href="#cb294-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">min</span> <span class="dv">5</span> <span class="dv">3</span></span>
|
||
<span id="cb294-8"><a href="#cb294-8" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb294-9"><a href="#cb294-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">max</span> <span class="dv">5</span> <span class="dv">3</span></span>
|
||
<span id="cb294-10"><a href="#cb294-10" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span></span>
|
||
<span id="cb294-11"><a href="#cb294-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="st">"aardvark"</span> <span class="op"><</span> <span class="st">"banana"</span> <span class="co">-- strings are compared alphabetically</span></span>
|
||
<span id="cb294-12"><a href="#cb294-12" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb294-13"><a href="#cb294-13" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</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">5</span>] <span class="co">-- lists are compared like strings</span></span>
|
||
<span id="cb294-14"><a href="#cb294-14" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb294-15"><a href="#cb294-15" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</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">1</span>,<span class="dv">1</span>]</span>
|
||
<span id="cb294-16"><a href="#cb294-16" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<p>When we can compare values, we can also sort lists of them. The
|
||
function <code>sort</code> from <code>Data.List</code> works on all
|
||
types that belong to the <code>Ord</code> class.</p>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Data.List</span></span>
|
||
<span id="cb295-2"><a href="#cb295-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.List</span><span class="op">></span> <span class="op">:</span>t <span class="fu">sort</span></span>
|
||
<span id="cb295-3"><a href="#cb295-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>
|
||
<span id="cb295-4"><a href="#cb295-4" 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">6</span>,<span class="dv">1</span>,<span class="dv">4</span>,<span class="dv">8</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb295-5"><a href="#cb295-5" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">4</span>,<span class="dv">6</span>,<span class="dv">8</span>]</span>
|
||
<span id="cb295-6"><a href="#cb295-6" 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="st">"black sphinx of quartz, judge my vow!"</span> <span class="co">-- remember, strings are lists!</span></span>
|
||
<span id="cb295-7"><a href="#cb295-7" aria-hidden="true" tabindex="-1"></a><span class="st">" !,aabcdefghijklmnoopqrstuuvwxyz"</span></span></code></pre></div>
|
||
<p>As a last example, let’s sort a list of lists according to length.
|
||
We’ll need two helper functions:</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="co">-- from the module Data.Ord</span></span>
|
||
<span id="cb296-2"><a href="#cb296-2" aria-hidden="true" tabindex="-1"></a><span class="co">-- compares two values "through" the function f</span></span>
|
||
<span id="cb296-3"><a href="#cb296-3" aria-hidden="true" tabindex="-1"></a><span class="ot">comparing ::</span> (<span class="dt">Ord</span> a) <span class="ot">=></span> (b <span class="ot">-></span> a) <span class="ot">-></span> b <span class="ot">-></span> b <span class="ot">-></span> <span class="dt">Ordering</span></span>
|
||
<span id="cb296-4"><a href="#cb296-4" aria-hidden="true" tabindex="-1"></a>comparing f x y <span class="ot">=</span> <span class="fu">compare</span> (f x) (f y)</span>
|
||
<span id="cb296-5"><a href="#cb296-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb296-6"><a href="#cb296-6" aria-hidden="true" tabindex="-1"></a><span class="co">-- from the module Data.List</span></span>
|
||
<span id="cb296-7"><a href="#cb296-7" aria-hidden="true" tabindex="-1"></a><span class="co">-- sorts a list using the given comparison function</span></span>
|
||
<span id="cb296-8"><a href="#cb296-8" aria-hidden="true" tabindex="-1"></a><span class="ot">sortBy ::</span> (a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Ordering</span>) <span class="ot">-></span> [a] <span class="ot">-></span> [a]</span></code></pre></div>
|
||
<p>Now the implementation of <code>sortByLength</code> is
|
||
straightforward:</p>
|
||
<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><span class="co">-- sorts lists by their length</span></span>
|
||
<span id="cb297-2"><a href="#cb297-2" aria-hidden="true" tabindex="-1"></a><span class="ot">sortByLength ::</span> [[a]] <span class="ot">-></span> [[a]]</span>
|
||
<span id="cb297-3"><a href="#cb297-3" aria-hidden="true" tabindex="-1"></a>sortByLength <span class="ot">=</span> sortBy (comparing <span class="fu">length</span>)</span></code></pre></div>
|
||
<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>sortByLength [[<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">4</span>,<span class="dv">5</span>,<span class="dv">6</span>,<span class="dv">7</span>]] <span class="op">==></span> [[<span class="dv">4</span>,<span class="dv">5</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></code></pre></div>
|
||
<h3 data-number="4.5.3" id="num-integral-fractional-floating"><span
|
||
class="header-section-number">4.5.3</span> <code>Num</code>,
|
||
<code>Integral</code>, <code>Fractional</code>,
|
||
<code>Floating</code></h3>
|
||
<p>The <code>Num</code> class contains integer arithmetic:</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">(+) ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb299-2"><a href="#cb299-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(-) ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb299-3"><a href="#cb299-3" aria-hidden="true" tabindex="-1"></a><span class="ot">(*) ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb299-4"><a href="#cb299-4" 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 class="co">-- 0-x</span></span>
|
||
<span id="cb299-5"><a href="#cb299-5" aria-hidden="true" tabindex="-1"></a><span class="fu">abs</span><span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="co">-- absolute value</span></span>
|
||
<span id="cb299-6"><a href="#cb299-6" aria-hidden="true" tabindex="-1"></a><span class="fu">signum</span><span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="co">-- -1 for negative values, 0 for 0, +1 for positive values</span></span>
|
||
<span id="cb299-7"><a href="#cb299-7" aria-hidden="true" tabindex="-1"></a><span class="fu">fromInteger</span><span class="ot"> ::</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Integer</span> <span class="ot">-></span> a</span></code></pre></div>
|
||
<p><code>Num</code> also shows up in the types of integer literals:</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dv">12</span></span>
|
||
<span id="cb300-2"><a href="#cb300-2" aria-hidden="true" tabindex="-1"></a><span class="dv">12</span><span class="ot"> ::</span> <span class="dt">Num</span> p <span class="ot">=></span> p</span></code></pre></div>
|
||
<p>This means that a literal like <code>12</code> can be interpreted as
|
||
a member of any type implementing <code>Num</code>. When GHC reads a
|
||
number literal like, <code>12</code> it produces code that corresponds
|
||
to <code>fromIntegral 12</code>.</p>
|
||
<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> <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Int</span></span>
|
||
<span id="cb301-2"><a href="#cb301-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb301-3"><a href="#cb301-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb301-4"><a href="#cb301-4" aria-hidden="true" tabindex="-1"></a><span class="fl">1.0</span></span>
|
||
<span id="cb301-5"><a href="#cb301-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">fromIntegral</span> <span class="dv">1</span><span class="ot"> ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb301-6"><a href="#cb301-6" aria-hidden="true" tabindex="-1"></a><span class="fl">1.0</span></span></code></pre></div>
|
||
<p><code>Integral</code> is the class of types that represent whole
|
||
numbers, like <code>Int</code> and <code>Integer</code>. The most
|
||
interesting functions are <code>div</code> and <code>mod</code> for
|
||
integer division and remainder. All types that belong to
|
||
<code>Integral</code> also belong to <code>Num</code>.</p>
|
||
<div class="sourceCode" id="cb302"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb302-1"><a href="#cb302-1" aria-hidden="true" tabindex="-1"></a><span class="fu">div</span><span class="ot"> ::</span> <span class="dt">Integral</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb302-2"><a href="#cb302-2" aria-hidden="true" tabindex="-1"></a><span class="fu">mod</span><span class="ot"> ::</span> <span class="dt">Integral</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<p><code>Fractional</code> is the class for types that have division.
|
||
All types that belong to <code>Fractional</code> also belong to
|
||
<code>Num</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">(/) ::</span> <span class="dt">Fractional</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<p><code>Floating</code> contains some additional operations that only
|
||
make sense for floating point numbers. All types that belong to
|
||
<code>Floating</code> also belong to <code>Fractional</code> (and to
|
||
<code>Num</code>).</p>
|
||
<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><span class="fu">sqrt</span><span class="ot"> ::</span> <span class="dt">Floating</span> a <span class="ot">=></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb304-2"><a href="#cb304-2" aria-hidden="true" tabindex="-1"></a><span class="fu">sin</span><span class="ot"> ::</span> <span class="dt">Floating</span> a <span class="ot">=></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<h3 data-number="4.5.4" id="read-and-show"><span
|
||
class="header-section-number">4.5.4</span> <code>Read</code> and
|
||
<code>Show</code></h3>
|
||
<p>The <code>Show</code> and <code>Read</code> classes are for the
|
||
functions <code>show</code> and <code>read</code>, that convert values
|
||
to and from Strings.</p>
|
||
<div class="sourceCode" id="cb305"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb305-1"><a href="#cb305-1" aria-hidden="true" tabindex="-1"></a><span class="fu">show</span><span class="ot"> ::</span> <span class="dt">Show</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb305-2"><a href="#cb305-2" aria-hidden="true" tabindex="-1"></a><span class="fu">read</span><span class="ot"> ::</span> <span class="dt">Read</span> a <span class="ot">=></span> <span class="dt">String</span> <span class="ot">-></span> a</span></code></pre></div>
|
||
<div class="sourceCode" id="cb306"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb306-1"><a href="#cb306-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">show</span> <span class="dv">3</span></span>
|
||
<span id="cb306-2"><a href="#cb306-2" aria-hidden="true" tabindex="-1"></a><span class="st">"3"</span></span>
|
||
<span id="cb306-3"><a href="#cb306-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">read</span> <span class="st">"3"</span><span class="ot"> ::</span> <span class="dt">Int</span></span>
|
||
<span id="cb306-4"><a href="#cb306-4" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb306-5"><a href="#cb306-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">read</span> <span class="st">"3"</span><span class="ot"> ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb306-6"><a href="#cb306-6" aria-hidden="true" tabindex="-1"></a><span class="fl">3.0</span></span></code></pre></div>
|
||
<p>As you can see above, you often need to use a type annotation with
|
||
<code>read</code> so that the compiler can choose the right
|
||
implementation.</p>
|
||
<h3 data-number="4.5.5" id="sidenote-foldable"><span
|
||
class="header-section-number">4.5.5</span> Sidenote:
|
||
<code>Foldable</code></h3>
|
||
<p>One more thing! You might remember that it was mentioned earlier that
|
||
the type of <code>length</code> isn’t <code>[a] -> Int</code> but
|
||
something more general. Let’s have a look:</p>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">length</span></span>
|
||
<span id="cb307-2"><a href="#cb307-2" 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></code></pre></div>
|
||
<p>This type looks a bit different than the ones we’ve seen before. The
|
||
type variable <code>t</code> has an argument <code>a</code>. We’ll look
|
||
at type classes like this in more detail in part 2, but here’s a crash
|
||
course.</p>
|
||
<p>What <code>Foldable</code> represents is types that you can fold
|
||
over. The true type of <code>foldr</code> is:</p>
|
||
<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="fu">foldr</span><span class="ot"> ::</span> <span class="dt">Foldable</span> t <span class="ot">=></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>We’ve succesfully used the fact that lists are <code>Foldable</code>
|
||
since we’ve managed to use <code>length</code> and <code>foldr</code> on
|
||
lists. However, <code>Maybe</code> is also <code>Foldable</code>! The
|
||
<code>Foldable</code> instance for <code>Maybe</code> just pretends that
|
||
values of <code>Maybe a</code> are like lists of length 0 or 1:</p>
|
||
<div class="sourceCode" id="cb309"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb309-1"><a href="#cb309-1" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">1</span> <span class="dt">Nothing</span> <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb309-2"><a href="#cb309-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">1</span> (<span class="dt">Just</span> <span class="dv">3</span>) <span class="op">==></span> <span class="dv">4</span></span>
|
||
<span id="cb309-3"><a href="#cb309-3" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> <span class="dt">Nothing</span> <span class="op">==></span> <span class="dv">0</span></span>
|
||
<span id="cb309-4"><a href="#cb309-4" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (<span class="dt">Just</span> <span class="ch">'a'</span>) <span class="op">==></span> <span class="dv">1</span></span></code></pre></div>
|
||
<p>We’ll meet some more foldable types next.</p>
|
||
<h2 data-number="4.6" id="more-data-structures"><span
|
||
class="header-section-number">4.6</span> More Data Structures</h2>
|
||
<p>Now that we are familiar with the standard type classes, we can look
|
||
at one of their applications: the <code>Map</code> and
|
||
<code>Array</code> data structures.</p>
|
||
<h3 data-number="4.6.1" id="data.map"><span
|
||
class="header-section-number">4.6.1</span> <code>Data.Map</code></h3>
|
||
<p>The <code>Data.Map</code> module defines the <code>Map</code> type.
|
||
Maps are search trees for key-value pairs. One way to look at this is
|
||
that a value of type <code>Map k v</code> is roughly the same as a value
|
||
of type <code>[(k,v)]</code>, a list of pairs. However, the operations
|
||
on a map are more efficient than operations on a list.</p>
|
||
<p>Since <code>Data.Map</code> contains some function with the same
|
||
names as <code>Prelude</code> functions, the namespace needs to be
|
||
imported <em>qualified</em>:</p>
|
||
<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="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></code></pre></div>
|
||
<p>Now we can refer to the map type as <code>Map.Map</code>, and to
|
||
various map functions like <code>Map.insert</code>. Here are the most
|
||
important functions for maps:</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="co">-- Create a Map from a list of key-value pairs</span></span>
|
||
<span id="cb311-2"><a href="#cb311-2" aria-hidden="true" tabindex="-1"></a>Map.fromList<span class="ot"> ::</span> <span class="dt">Ord</span> k <span class="ot">=></span> [(k, a)] <span class="ot">-></span> <span class="dt">Map.Map</span> k a</span>
|
||
<span id="cb311-3"><a href="#cb311-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb311-4"><a href="#cb311-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- Insert a value into a map. Overrides any previous value with the same key.</span></span>
|
||
<span id="cb311-5"><a href="#cb311-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- Returns a new map. Does not mutate the given map.</span></span>
|
||
<span id="cb311-6"><a href="#cb311-6" aria-hidden="true" tabindex="-1"></a>Map.insert<span class="ot"> ::</span> <span class="dt">Ord</span> k <span class="ot">=></span> k <span class="ot">-></span> a <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>
|
||
<span id="cb311-7"><a href="#cb311-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb311-8"><a href="#cb311-8" aria-hidden="true" tabindex="-1"></a><span class="co">-- Get a value from a map using a key. Returns Nothing if the key was not present in the map.</span></span>
|
||
<span id="cb311-9"><a href="#cb311-9" aria-hidden="true" tabindex="-1"></a>Map.lookup<span class="ot"> ::</span> <span class="dt">Ord</span> k <span class="ot">=></span> k <span class="ot">-></span> <span class="dt">Map.Map</span> k a <span class="ot">-></span> <span class="dt">Maybe</span> a</span>
|
||
<span id="cb311-10"><a href="#cb311-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb311-11"><a href="#cb311-11" aria-hidden="true" tabindex="-1"></a><span class="co">-- An empty map</span></span>
|
||
<span id="cb311-12"><a href="#cb311-12" aria-hidden="true" tabindex="-1"></a>Map.empty<span class="ot"> ::</span> <span class="dt">Map.Map</span> k a</span></code></pre></div>
|
||
<p>The <code>Ord</code> constraint for the key type of the map is needed
|
||
because maps are implemented as <em>ordered binary search
|
||
trees</em>.</p>
|
||
<p>Note that like all Haskell values, maps are <em>immutable</em>
|
||
meaning you can’t change a map once you define it. However, map
|
||
operations like <code>insert</code> produce a <em>new</em> map. To
|
||
perform multiple map operations you need to reuse the return value.
|
||
Here’s a GHCi session operating on a map.</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.Map</span> <span class="kw">as</span> <span class="dt">Map</span></span>
|
||
<span id="cb312-2"><a href="#cb312-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> values <span class="ot">=</span> Map.fromList [(<span class="st">"z"</span>,<span class="dv">3</span>),(<span class="st">"w"</span>,<span class="dv">4</span>)]</span>
|
||
<span id="cb312-3"><a href="#cb312-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> Map.lookup <span class="st">"z"</span> values</span>
|
||
<span id="cb312-4"><a href="#cb312-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Just</span> <span class="dv">3</span></span>
|
||
<span id="cb312-5"><a href="#cb312-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> Map.lookup <span class="st">"banana"</span> values</span>
|
||
<span id="cb312-6"><a href="#cb312-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Nothing</span></span>
|
||
<span id="cb312-7"><a href="#cb312-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> Map.insert <span class="st">"x"</span> <span class="dv">7</span> values</span>
|
||
<span id="cb312-8"><a href="#cb312-8" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"w"</span>,<span class="dv">4</span>),(<span class="st">"x"</span>,<span class="dv">7</span>),(<span class="st">"z"</span>,<span class="dv">3</span>)]</span>
|
||
<span id="cb312-9"><a href="#cb312-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> values <span class="co">-- note immutability!</span></span>
|
||
<span id="cb312-10"><a href="#cb312-10" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"w"</span>,<span class="dv">4</span>),(<span class="st">"z"</span>,<span class="dv">3</span>)]</span>
|
||
<span id="cb312-11"><a href="#cb312-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span> Map.insert <span class="st">"x"</span> <span class="dv">1</span> (Map.insert <span class="st">"y"</span> <span class="dv">2</span> values) <span class="co">-- two insertions</span></span>
|
||
<span id="cb312-12"><a href="#cb312-12" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"w"</span>,<span class="dv">4</span>),(<span class="st">"x"</span>,<span class="dv">1</span>),(<span class="st">"y"</span>,<span class="dv">2</span>),(<span class="st">"z"</span>,<span class="dv">3</span>)]</span>
|
||
<span id="cb312-13"><a href="#cb312-13" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Map</span><span class="op">></span></span></code></pre></div>
|
||
<p>Here’s an example of representing a bank as a
|
||
<code>Map String Int</code> (map from account name to account balance),
|
||
and withdrawing some money from an account:</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="ot">withdraw ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span></span>
|
||
<span id="cb313-2"><a href="#cb313-2" aria-hidden="true" tabindex="-1"></a>withdraw account amount bank <span class="ot">=</span></span>
|
||
<span id="cb313-3"><a href="#cb313-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">case</span> Map.lookup account bank <span class="kw">of</span></span>
|
||
<span id="cb313-4"><a href="#cb313-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Nothing</span> <span class="ot">-></span> bank <span class="co">-- account not found, no change</span></span>
|
||
<span id="cb313-5"><a href="#cb313-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">Just</span> <span class="fu">sum</span> <span class="ot">-></span> Map.insert account (<span class="fu">sum</span><span class="op">-</span>amount) bank <span class="co">-- set new balance</span></span></code></pre></div>
|
||
<p>Here’s how you might use the <code>withdraw</code> function in
|
||
<code>GHCi</code>. Note how the maps get printed as
|
||
<code>fromList</code> invocations. Also note how calling
|
||
<code>withdraw ... bank</code> returns a <em>new</em> bank and doesn’t
|
||
change the existing bank.</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">GHCi</span><span class="op">></span> bank <span class="ot">=</span> Map.fromList [(<span class="st">"Bob"</span>,<span class="dv">100</span>),(<span class="st">"Mike"</span>,<span class="dv">50</span>)]</span>
|
||
<span id="cb314-2"><a href="#cb314-2" aria-hidden="true" tabindex="-1"></a><span class="dt">GHCi</span><span class="op">></span> withdraw <span class="st">"Bob"</span> <span class="dv">80</span> bank</span>
|
||
<span id="cb314-3"><a href="#cb314-3" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"Bob"</span>,<span class="dv">20</span>),(<span class="st">"Mike"</span>,<span class="dv">50</span>)]</span>
|
||
<span id="cb314-4"><a href="#cb314-4" aria-hidden="true" tabindex="-1"></a><span class="dt">GHCi</span><span class="op">></span> bank <span class="co">-- note immutability</span></span>
|
||
<span id="cb314-5"><a href="#cb314-5" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"Bob"</span>,<span class="dv">100</span>),(<span class="st">"Mike"</span>,<span class="dv">50</span>)]</span>
|
||
<span id="cb314-6"><a href="#cb314-6" aria-hidden="true" tabindex="-1"></a><span class="dt">GHCi</span><span class="op">></span> withdraw <span class="st">"Bozo"</span> <span class="dv">1000</span> bank</span>
|
||
<span id="cb314-7"><a href="#cb314-7" aria-hidden="true" tabindex="-1"></a>fromList [(<span class="st">"Bob"</span>,<span class="dv">100</span>),(<span class="st">"Mike"</span>,<span class="dv">50</span>)]</span></code></pre></div>
|
||
<p><code>Data.Map</code> defines all sorts of useful higher-order
|
||
functions for updating maps. We can rewrite the <code>withdraw</code>
|
||
function using <code>Data.Map.adjust</code>:</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">withdraw ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Map.Map</span> <span class="dt">String</span> <span class="dt">Int</span></span>
|
||
<span id="cb315-2"><a href="#cb315-2" aria-hidden="true" tabindex="-1"></a>withdraw account amount bank <span class="ot">=</span> Map.adjust (\x <span class="ot">-></span> x<span class="op">-</span>amount) account bank</span></code></pre></div>
|
||
<p><strong>Note!</strong> There are separate
|
||
<code>Data.Map.Strict</code> and <code>Data.Map.Lazy</code>
|
||
implementations. When you import <code>Data.Map</code> you get
|
||
<code>Data.Map.Lazy</code>. You can find the documentation for all the
|
||
<code>Data.Map</code> functions in <a
|
||
href="https://hackage.haskell.org/package/containers-0.6.5.1/docs/Data-Map-Lazy.html">the
|
||
docs for <code>Data.Map.Lazy</code></a>. We won’t go into their
|
||
differences here, but mostly you should use <code>Data.Map.Strict</code>
|
||
in real code.</p>
|
||
<h3 data-number="4.6.2" id="data.array"><span
|
||
class="header-section-number">4.6.2</span> <code>Data.Array</code></h3>
|
||
<p>Another type that works kind of like a list but is more efficient for
|
||
some operations is the array. Arrays are familiar from many other
|
||
programming languages, but Haskell arrays are a bit different.</p>
|
||
<p>Unlike the <code>Data.Map</code> module, the <code>Data.Array</code>
|
||
can just be imported normally:</p>
|
||
<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="kw">import</span> <span class="dt">Data.Array</span></span></code></pre></div>
|
||
<p>Now we can look at the type of the <code>array</code> function that
|
||
constructs an array.</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="ot">array ::</span> <span class="dt">Ix</span> i <span class="ot">=></span> (i, i) <span class="ot">-></span> [(i, e)] <span class="ot">-></span> <span class="dt">Array</span> i e</span></code></pre></div>
|
||
<p>There are a couple of things to notice here. First of all, the
|
||
<code>Array</code> type is parameterized by <em>two</em> types: the
|
||
index type and the element type. Most other programming languages only
|
||
parameterize arrays with the element type, but the index type is always
|
||
<code>int</code>. In Haskell, we can have, for example, an
|
||
<code>Array Char Int</code>: an array indexed by characters, or
|
||
<code>Array Bool String</code>, an array indexed by booleans, or even
|
||
<code>Array (Int,Int) Int</code>, a two-dimensional array of ints.</p>
|
||
<p>Not all types can be index types. Only types that are similar to
|
||
integers are suitable. That is the reason for the <code>Ix i</code>
|
||
class constraint. The <code>Ix</code> class collects all the types that
|
||
can be used as array indices.</p>
|
||
<p>Secondly, the <code>array</code> function takes an extra
|
||
<code>(i,i)</code> parameter. These are the minimum and maximum indices
|
||
of the array. Unlike some other languages, where arrays always start at
|
||
index 0 or 1, in Haskell you can define an array that starts from 7 and
|
||
goes to 11. So here’s that array:</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="ot">myArray ::</span> <span class="dt">Array</span> <span class="dt">Int</span> <span class="dt">String</span></span>
|
||
<span id="cb318-2"><a href="#cb318-2" aria-hidden="true" tabindex="-1"></a>myArray <span class="ot">=</span> array (<span class="dv">7</span>,<span class="dv">11</span>) [(<span class="dv">7</span>,<span class="st">"seven"</span>), (<span class="dv">8</span>,<span class="st">"eight"</span>), (<span class="dv">9</span>,<span class="st">"nine"</span>), (<span class="dv">10</span>,<span class="st">"ten"</span>), (<span class="dv">11</span>,<span class="st">"ELEVEN"</span>)]</span></code></pre></div>
|
||
<p>Listing all the indices and elements in order can be a bit
|
||
cumbersome, so there’s also the <code>listArray</code> constructor that
|
||
just takes a list of elements in order:</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="ot">listArray ::</span> <span class="dt">Ix</span> i <span class="ot">=></span> (i, i) <span class="ot">-></span> [e] <span class="ot">-></span> <span class="dt">Array</span> i e</span></code></pre></div>
|
||
<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="ot">myArray ::</span> <span class="dt">Array</span> <span class="dt">Int</span> <span class="dt">String</span></span>
|
||
<span id="cb320-2"><a href="#cb320-2" aria-hidden="true" tabindex="-1"></a>myArray <span class="ot">=</span> listArray (<span class="dv">7</span>,<span class="dv">11</span>) [<span class="st">"seven"</span>, <span class="st">"eight"</span>, <span class="st">"nine"</span>, <span class="st">"ten"</span>, <span class="st">"ELEVEN"</span>]</span></code></pre></div>
|
||
<p>Arrays are used with two new operators:</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="co">-- Array lookup</span></span>
|
||
<span id="cb321-2"><a href="#cb321-2" aria-hidden="true" tabindex="-1"></a><span class="ot">(!) ::</span> <span class="dt">Ix</span> i <span class="ot">=></span> <span class="dt">Array</span> i e <span class="ot">-></span> i <span class="ot">-></span> e</span>
|
||
<span id="cb321-3"><a href="#cb321-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- Array update</span></span>
|
||
<span id="cb321-4"><a href="#cb321-4" aria-hidden="true" tabindex="-1"></a><span class="ot">(//) ::</span> <span class="dt">Ix</span> i <span class="ot">=></span> <span class="dt">Array</span> i e <span class="ot">-></span> [(i, e)] <span class="ot">-></span> <span class="dt">Array</span> i e</span></code></pre></div>
|
||
<p>Here’s an example <code>GHCi</code> session:</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="op">></span> <span class="kw">import</span> <span class="dt">Data.Array</span></span>
|
||
<span id="cb322-2"><a href="#cb322-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Array</span><span class="op">></span> myArray <span class="ot">=</span> listArray (<span class="dv">7</span>,<span class="dv">11</span>) [<span class="st">"seven"</span>, <span class="st">"eight"</span>, <span class="st">"nine"</span>, <span class="st">"ten"</span>, <span class="st">"ELEVEN"</span>]</span>
|
||
<span id="cb322-3"><a href="#cb322-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Array</span><span class="op">></span> myArray</span>
|
||
<span id="cb322-4"><a href="#cb322-4" aria-hidden="true" tabindex="-1"></a>array (<span class="dv">7</span>,<span class="dv">11</span>) [(<span class="dv">7</span>,<span class="st">"seven"</span>),(<span class="dv">8</span>,<span class="st">"eight"</span>),(<span class="dv">9</span>,<span class="st">"nine"</span>),(<span class="dv">10</span>,<span class="st">"ten"</span>),(<span class="dv">11</span>,<span class="st">"ELEVEN"</span>)]</span>
|
||
<span id="cb322-5"><a href="#cb322-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Array</span><span class="op">></span> myArray <span class="op">!</span> <span class="dv">8</span></span>
|
||
<span id="cb322-6"><a href="#cb322-6" aria-hidden="true" tabindex="-1"></a><span class="st">"eight"</span></span>
|
||
<span id="cb322-7"><a href="#cb322-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Array</span><span class="op">></span> myArray <span class="op">//</span> [(<span class="dv">8</span>,<span class="st">"ocho"</span>),(<span class="dv">9</span>,<span class="st">"nueve"</span>)]</span>
|
||
<span id="cb322-8"><a href="#cb322-8" aria-hidden="true" tabindex="-1"></a>array (<span class="dv">7</span>,<span class="dv">11</span>) [(<span class="dv">7</span>,<span class="st">"seven"</span>),(<span class="dv">8</span>,<span class="st">"ocho"</span>),(<span class="dv">9</span>,<span class="st">"nueve"</span>),(<span class="dv">10</span>,<span class="st">"ten"</span>),(<span class="dv">11</span>,<span class="st">"ELEVEN"</span>)]</span></code></pre></div>
|
||
<p>You might be wondering why the <code>(//)</code> operator does
|
||
multiple updates at once. The reason is the main weakness of Haskell
|
||
arrays: immutability. Since arrays can’t be changed in place,
|
||
<code>(//)</code> must copy the whole array. This is why in Haskell it’s
|
||
often preferable to use lists or maps to store data that needs to be
|
||
updated. However, arrays may still be useful when constructed once and
|
||
then used for a large number of lookups. We’ll get back to how Haskell
|
||
data structures work in the next lecture.</p>
|
||
<p><strong>Note!</strong> In this course we’ll use only
|
||
<code>Array</code>, a simple array type that’s specified in the Haskell
|
||
standard. There are many other array types like the mutable
|
||
<code>IOArray</code> and the somewhat obscure <code>DiffArray</code>.
|
||
There are also type classes for arrays like <code>IArray</code> and
|
||
<code>MArray</code>. In addition to arrays there is a <a
|
||
href="https://hackage.haskell.org/package/vector">wide family of
|
||
<code>Vector</code> types</a> that can be more practical than
|
||
<code>Array</code> for real programs.</p>
|
||
<h3 data-number="4.6.3" id="sidenote-folding-over-maps-arrays"><span
|
||
class="header-section-number">4.6.3</span> Sidenote: Folding over Maps
|
||
& Arrays</h3>
|
||
<p>The <code>Map</code> and <code>Array</code> type are instances of
|
||
<code>Foldable</code> just like lists are! This means you can use
|
||
functions like <code>length</code> and <code>foldr</code> on them:</p>
|
||
<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><span class="fu">length</span> (array (<span class="dv">7</span>,<span class="dv">11</span>) [(<span class="dv">7</span>,<span class="st">"seven"</span>),(<span class="dv">8</span>,<span class="st">"eight"</span>),(<span class="dv">9</span>,<span class="st">"nine"</span>),(<span class="dv">10</span>,<span class="st">"ten"</span>),(<span class="dv">11</span>,<span class="st">"ELEVEN"</span>)])</span>
|
||
<span id="cb323-2"><a href="#cb323-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">5</span></span>
|
||
<span id="cb323-3"><a href="#cb323-3" aria-hidden="true" tabindex="-1"></a><span class="fu">foldr</span> (<span class="op">+</span>) <span class="dv">0</span> (Map.fromList [(<span class="st">"banana"</span>,<span class="dv">3</span>),(<span class="st">"egg"</span>,<span class="dv">7</span>)])</span>
|
||
<span id="cb323-4"><a href="#cb323-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">10</span></span></code></pre></div>
|
||
<h2 data-number="4.7" id="reading-docs"><span
|
||
class="header-section-number">4.7</span> Reading Docs</h2>
|
||
<p>Haskell libraries tend to have pretty good docs. We’ve linked to docs
|
||
via Hackage (<a href="https://hackage.haskell.org"
|
||
class="uri">https://hackage.haskell.org</a>) previously, but it’s
|
||
important to know how to find the docs by yourself too. The tool for
|
||
generating Haskell documentation is called <em>Haddock</em> so sometimes
|
||
Haskell docs are referred to as <em>haddocks</em>.</p>
|
||
<p>Hackage is the Haskell package repository (just like <a
|
||
href="https://pypi.org/">PyPI</a> for Python, Maven Central for Java or
|
||
<a href="https://npmjs.com">NPM</a> for Javascript). In addition to the
|
||
actual packages, it hosts documentation for them. Most of the modules
|
||
that we use on this course are in the package called <code>base</code>.
|
||
You can browse the docs for the base package at <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/"
|
||
class="uri">https://hackage.haskell.org/package/base-4.16.4.0/</a>.</p>
|
||
<p>When you’re not quite sure where the function you’re looking for is,
|
||
Hoogle (<a href="https://hoogle.haskell.org/"
|
||
class="uri">https://hoogle.haskell.org/</a>) can help. Hoogle is a
|
||
search engine for Haskell documentation. It is a great resource when you
|
||
need to check what was the type of <code>foldr</code> or which packages
|
||
contain a function named <code>reverse</code>.</p>
|
||
<p>Finally, since this course is using the <code>stack</code> tool, you
|
||
can also browse the documentation for the libraries stack has installed
|
||
for you with the commands</p>
|
||
<pre><code>stack haddock --open
|
||
stack haddock --open <package></code></pre>
|
||
<p>This has the added benefit of getting exactly the right version of
|
||
the documentation.</p>
|
||
<p>In summary, here are the main ways of reading Haskell library
|
||
documentation:</p>
|
||
<ul>
|
||
<li>If you know the name of the package you browse the docs via <a
|
||
href="https://hackage.haskell.org/"
|
||
class="uri">https://hackage.haskell.org/</a>.</li>
|
||
<li>If you know the name of the function you can find it using <a
|
||
href="https://hoogle.haskell.org/"
|
||
class="uri">https://hoogle.haskell.org/</a>.</li>
|
||
<li>If you’re using <code>stack</code> you can use
|
||
<code>stack haddock --open</code> or
|
||
<code>stack haddock --open <package></code> to open docs in your
|
||
browser.</li>
|
||
</ul>
|
||
<h2 data-number="4.8" id="quiz-3"><span
|
||
class="header-section-number">4.8</span> Quiz</h2>
|
||
<p>What is the type of <code>swap . swap</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>(a, b) -> (a, b)</code>
|
||
</li>
|
||
<li>
|
||
<code>(a, b) -> (b, a)</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> a</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of <code>\f g x -> (f x, g x)</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>(a -> b) -> (c -> d) -> (a,c) -> (b, d)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(a -> b) -> (a -> c) -> a -> (b, c)</code>
|
||
</li>
|
||
<li>
|
||
<code>(a -> b) -> (b -> a) -> a -> (b, a)</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of
|
||
<code>\t -> (fst . fst $ t, (snd . fst $ t, snd t))</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>(a, (b, c)) -> (a, (b, c))</code>
|
||
</li>
|
||
<li>
|
||
<code>(a, (b, c)) -> ((a, b), c)</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>((a, b), c) -> (a, (b, c))</code>
|
||
</li>
|
||
</ol>
|
||
<p>What does the function <code>foldr (\x xs -> xs ++ [x]) []</code>
|
||
do?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
It doesn’t change its input list at all
|
||
</li>
|
||
<li>
|
||
It changes the associativity of a list from left to right
|
||
</li>
|
||
<li class="correct">
|
||
It reverses its input list
|
||
</li>
|
||
</ol>
|
||
<p>What does the function
|
||
<code>foldr (\(x, y) zs -> x : y : zs) []</code> do?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
It turns a list of pairs into a pair of lists
|
||
</li>
|
||
<li>
|
||
It turns a pair of lists into a list of pairs
|
||
</li>
|
||
<li class="correct">
|
||
It turns a list of pairs into a list of elements
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of
|
||
<code>foldr (\n b -> n == 3 && b)</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>(Foldable t, Eq a, Num a) => Bool -> t a -> Bool</code>
|
||
</li>
|
||
<li>
|
||
<code>(Foldable t, Eq a, Num a, Bool b) => b -> t a -> b</code>
|
||
</li>
|
||
<li>
|
||
<code>(Foldable t, Eq a, Num a) => Bool -> [ a ] -> Bool</code>
|
||
</li>
|
||
</ol>
|
||
<p>What is the type of
|
||
<code>\x -> case x of (True, "Foo") -> show True ++ "Foo"</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Either Bool String -> String</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>(Bool, String) -> String</code>
|
||
</li>
|
||
<li>
|
||
<code>Show a => (Bool, String) -> a</code>
|
||
</li>
|
||
</ol>
|
||
<!-- TODO more, maybe some Array and Map questions -->
|
||
<h2 data-number="4.9" id="exercises-3"><span
|
||
class="header-section-number">4.9</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set4a.hs">Set4a</a>:
|
||
type classes</li>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set4b.hs">Set4b</a>:
|
||
folds</li>
|
||
</ul>
|
||
<h1 data-number="5" id="lecture-5-you-need-string-for-a-knot"><span
|
||
class="header-section-number">5</span> Lecture 5: You Need String for a
|
||
Knot</h1>
|
||
<ul>
|
||
<li>Type system</li>
|
||
<li>Defining custom types</li>
|
||
</ul>
|
||
<h2 data-number="5.1" id="algebraic-datatypes"><span
|
||
class="header-section-number">5.1</span> Algebraic Datatypes</h2>
|
||
<p>Haskell has a system called <em>algebraic datatypes</em> for defining
|
||
new types. This sounds fancy, but is rather simple. Let’s dive in by
|
||
looking at the standard library definitions of some familiar types:</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="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="cb325-2"><a href="#cb325-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Ordering</span> <span class="ot">=</span> <span class="dt">LT</span> <span class="op">|</span> <span class="dt">EQ</span> <span class="op">|</span> <span class="dt">GT</span></span></code></pre></div>
|
||
<p>With this syntax you too can define types:</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="co">-- definition of a type with three values</span></span>
|
||
<span id="cb326-2"><a href="#cb326-2" 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="cb326-3"><a href="#cb326-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb326-4"><a href="#cb326-4" aria-hidden="true" tabindex="-1"></a><span class="co">-- a function that uses pattern matching on our new type</span></span>
|
||
<span id="cb326-5"><a href="#cb326-5" aria-hidden="true" tabindex="-1"></a><span class="ot">rgb ::</span> <span class="dt">Color</span> <span class="ot">-></span> [<span class="dt">Double</span>]</span>
|
||
<span id="cb326-6"><a href="#cb326-6" aria-hidden="true" tabindex="-1"></a>rgb <span class="dt">Red</span> <span class="ot">=</span> [<span class="dv">1</span>,<span class="dv">0</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb326-7"><a href="#cb326-7" aria-hidden="true" tabindex="-1"></a>rgb <span class="dt">Green</span> <span class="ot">=</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">0</span>]</span>
|
||
<span id="cb326-8"><a href="#cb326-8" aria-hidden="true" tabindex="-1"></a>rgb <span class="dt">Blue</span> <span class="ot">=</span> [<span class="dv">0</span>,<span class="dv">0</span>,<span class="dv">1</span>]</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Red</span></span>
|
||
<span id="cb327-2"><a href="#cb327-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Red</span><span class="ot"> ::</span> <span class="dt">Color</span></span>
|
||
<span id="cb327-3"><a href="#cb327-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t [<span class="dt">Red</span>,<span class="dt">Blue</span>,<span class="dt">Green</span>]</span>
|
||
<span id="cb327-4"><a href="#cb327-4" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Red</span>,<span class="dt">Blue</span>,<span class="dt">Green</span>]<span class="ot"> ::</span> [<span class="dt">Color</span>]</span>
|
||
<span id="cb327-5"><a href="#cb327-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> rgb <span class="dt">Red</span></span>
|
||
<span id="cb327-6"><a href="#cb327-6" aria-hidden="true" tabindex="-1"></a>[<span class="fl">1.0</span>,<span class="fl">0.0</span>,<span class="fl">0.0</span>]</span></code></pre></div>
|
||
<h3 data-number="5.1.1" id="fields"><span
|
||
class="header-section-number">5.1.1</span> Fields</h3>
|
||
<p>Types like <code>Bool</code>, <code>Ordering</code> and
|
||
<code>Color</code> that just list a bunch of constants are called
|
||
<em>enumerations</em> or <em>enums</em> in Haskell and other languages.
|
||
Enums are useful, but you need other types as well. Here we define a
|
||
type for reports containing an id number, a title, and a body:</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="kw">data</span> <span class="dt">Report</span> <span class="ot">=</span> <span class="dt">ConstructReport</span> <span class="dt">Int</span> <span class="dt">String</span> <span class="dt">String</span></span></code></pre></div>
|
||
<p>This is how you create a report:</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="op">></span> <span class="op">:</span>t <span class="dt">ConstructReport</span> <span class="dv">1</span> <span class="st">"Title"</span> <span class="st">"This is the body."</span></span>
|
||
<span id="cb329-2"><a href="#cb329-2" aria-hidden="true" tabindex="-1"></a><span class="dt">ConstructReport</span> <span class="dv">1</span> <span class="st">"Title"</span> <span class="st">"This is the body."</span><span class="ot"> ::</span> <span class="dt">Report</span></span></code></pre></div>
|
||
<p>You can access the fields with pattern matching:</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="ot">reportContents ::</span> <span class="dt">Report</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb330-2"><a href="#cb330-2" aria-hidden="true" tabindex="-1"></a>reportContents (<span class="dt">ConstructReport</span> <span class="fu">id</span> title contents) <span class="ot">=</span> contents</span>
|
||
<span id="cb330-3"><a href="#cb330-3" aria-hidden="true" tabindex="-1"></a><span class="ot">setReportContents ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Report</span> <span class="ot">-></span> <span class="dt">Report</span></span>
|
||
<span id="cb330-4"><a href="#cb330-4" aria-hidden="true" tabindex="-1"></a>setReportContents contents (<span class="dt">ConstructReport</span> <span class="fu">id</span> title _contents) <span class="ot">=</span> <span class="dt">ConstructReport</span> <span class="fu">id</span> title contents</span></code></pre></div>
|
||
<h3 data-number="5.1.2" id="constructors"><span
|
||
class="header-section-number">5.1.2</span> Constructors</h3>
|
||
<p>The things on the right hand side of a <code>data</code> declaration
|
||
are called <em>constructors</em>. <code>True</code>, <code>False</code>,
|
||
<code>Red</code> and <code>ConstructReport</code> are all examples of
|
||
constructors. A type can have multiple constructors, and a constructor
|
||
can have zero or more fields.</p>
|
||
<p>Here is a datatype for a standard playing card. It has five
|
||
constructors, of which <code>Joker</code> has zero fields and the others
|
||
have one field.</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">data</span> <span class="dt">Card</span> <span class="ot">=</span> <span class="dt">Joker</span> <span class="op">|</span> <span class="dt">Heart</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Club</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Spade</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Diamond</span> <span class="dt">Int</span></span></code></pre></div>
|
||
<p>Constructors with fields have function type and can be used wherever
|
||
functions can:</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="op">></span> <span class="op">:</span>t <span class="dt">Heart</span></span>
|
||
<span id="cb332-2"><a href="#cb332-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Heart</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Card</span></span>
|
||
<span id="cb332-3"><a href="#cb332-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Club</span></span>
|
||
<span id="cb332-4"><a href="#cb332-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Club</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Card</span></span>
|
||
<span id="cb332-5"><a href="#cb332-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</span> <span class="dt">Heart</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb332-6"><a href="#cb332-6" aria-hidden="true" tabindex="-1"></a>[<span class="dt">Heart</span> <span class="dv">1</span>,<span class="dt">Heart</span> <span class="dv">2</span>,<span class="dt">Heart</span> <span class="dv">3</span>]</span>
|
||
<span id="cb332-7"><a href="#cb332-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> (<span class="dt">Heart</span> <span class="op">.</span> (\x <span class="ot">-></span> x<span class="op">+</span><span class="dv">1</span>)) <span class="dv">3</span></span>
|
||
<span id="cb332-8"><a href="#cb332-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Heart</span> <span class="dv">4</span></span></code></pre></div>
|
||
<h3 data-number="5.1.3" id="sidenote-deriving"><span
|
||
class="header-section-number">5.1.3</span> Sidenote: Deriving</h3>
|
||
<p>By the way, there’s something missing from our <code>Card</code>
|
||
type. Look at how it behaves compared to <code>Ordering</code> and
|
||
<code>Bool</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="op">></span> <span class="dt">EQ</span></span>
|
||
<span id="cb333-2"><a href="#cb333-2" aria-hidden="true" tabindex="-1"></a><span class="dt">EQ</span></span>
|
||
<span id="cb333-3"><a href="#cb333-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">True</span></span>
|
||
<span id="cb333-4"><a href="#cb333-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb333-5"><a href="#cb333-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Joker</span></span>
|
||
<span id="cb333-6"><a href="#cb333-6" 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">0</span><span class="op">:</span></span>
|
||
<span id="cb333-7"><a href="#cb333-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Show</span> <span class="dt">Card</span>)</span>
|
||
<span id="cb333-8"><a href="#cb333-8" aria-hidden="true" tabindex="-1"></a> arising from a use <span class="kw">of</span> <span class="ot">`print' at <interactive>:1:0-4</span></span>
|
||
<span id="cb333-9"><a href="#cb333-9" aria-hidden="true" tabindex="-1"></a><span class="ot"> Possible fix: add an instance declaration for (Show Card)</span></span>
|
||
<span id="cb333-10"><a href="#cb333-10" aria-hidden="true" tabindex="-1"></a><span class="ot"> In a stmt of a 'do' expression: print it</span></span></code></pre></div>
|
||
<p>The problem is that Haskell does not know how to print the types we
|
||
defined. As the error says, they are not part of the <code>Show</code>
|
||
class. The easy solution is to just add a <code>deriving Show</code>
|
||
after the type definition:</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="kw">data</span> <span class="dt">Card</span> <span class="ot">=</span> <span class="dt">Joker</span> <span class="op">|</span> <span class="dt">Heart</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Club</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Spade</span> <span class="dt">Int</span> <span class="op">|</span> <span class="dt">Diamond</span> <span class="dt">Int</span></span>
|
||
<span id="cb334-2"><a href="#cb334-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="dt">Joker</span></span>
|
||
<span id="cb335-2"><a href="#cb335-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Joker</span></span></code></pre></div>
|
||
<p>The <code>deriving</code> syntax is a way to automatically make your
|
||
class a member of certain basic type classes, most notably
|
||
<code>Read</code>, <code>Show</code> and <code>Eq</code>. We’ll talk
|
||
more about what this means later.</p>
|
||
<h3 data-number="5.1.4" id="algebraic"><span
|
||
class="header-section-number">5.1.4</span> Algebraic?</h3>
|
||
<p>So why are these datatypes called algebraic? This is because,
|
||
theoretically speaking, each datatype can be a <em>sum</em> of
|
||
constructors, and each constructor is a <em>product</em> of fields. It
|
||
makes sense to think of these as sums and products for many reasons, one
|
||
being that we can count the possible values of each type this way:</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="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 class="co">-- corresponds to 1+1. Has 2 possible values.</span></span>
|
||
<span id="cb336-2"><a href="#cb336-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">TwoBools</span> <span class="ot">=</span> <span class="dt">TwoBools</span> <span class="dt">Bool</span> <span class="dt">Bool</span> <span class="co">-- corresponds to Bool*Bool, i.e. 2*2. Has 4 possible values.</span></span>
|
||
<span id="cb336-3"><a href="#cb336-3" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Complex</span> <span class="ot">=</span> <span class="dt">Two</span> <span class="dt">Bool</span> <span class="dt">Bool</span> <span class="op">|</span> <span class="dt">One</span> <span class="dt">Bool</span> <span class="op">|</span> <span class="dt">None</span></span>
|
||
<span id="cb336-4"><a href="#cb336-4" aria-hidden="true" tabindex="-1"></a> <span class="co">-- corresponds to Bool*Bool+Bool+1 = 2*2+2+1 = 7. Has 7 possible values.</span></span></code></pre></div>
|
||
<p>There is a rich theory of algebraic datatypes. If you’re interested,
|
||
you might find more info <a
|
||
href="https://codewords.recurse.com/issues/three/algebra-and-calculus-of-algebraic-data-types">here</a>
|
||
or <a
|
||
href="https://www.cis.upenn.edu/~sweirich/papers/yorgey-thesis.pdf">here</a>.</p>
|
||
<h2 data-number="5.2" id="type-parameters"><span
|
||
class="header-section-number">5.2</span> Type Parameters</h2>
|
||
<p>We introduced type parameters and parametric polymorphism when
|
||
introducing lists in Lecture 2. Since then, we’ve seen other
|
||
parameterized types like <code>Maybe</code> and <code>Either</code>. Now
|
||
we’ll learn how we can define our own parameterized types.</p>
|
||
<h3 data-number="5.2.1" id="defining-parameterized-types"><span
|
||
class="header-section-number">5.2.1</span> Defining Parameterized
|
||
Types</h3>
|
||
<p>The definition for <code>Maybe</code> is:</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="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></code></pre></div>
|
||
<p>What’s <code>a</code>? We define a parameterized type by mentioning a
|
||
<em>type variable</em> (<code>a</code> in this case) on the left side of
|
||
the <code>=</code> sign. We can then use the same type variable in
|
||
fields for our constructors. This is analogous to polymorphic functions.
|
||
Instead of defining separate functions</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">headInt ::</span> [<span class="dt">Int</span>] <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb338-2"><a href="#cb338-2" aria-hidden="true" tabindex="-1"></a><span class="ot">headBool ::</span> [<span class="dt">Bool</span>] <span class="ot">-></span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<p>and so on, we define one function <code>head :: [a] -> a</code>
|
||
that works for all types <code>a</code>. Similarly, instead of defining
|
||
multiple types</p>
|
||
<div class="sourceCode" id="cb339"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb339-1"><a href="#cb339-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">MaybeInt</span> <span class="ot">=</span> <span class="dt">NothingInt</span> <span class="op">|</span> <span class="dt">JustInt</span> <span class="dt">Int</span></span>
|
||
<span id="cb339-2"><a href="#cb339-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">MaybeBool</span> <span class="ot">=</span> <span class="dt">NothingBool</span> <span class="op">|</span> <span class="dt">JustBool</span> <span class="dt">Bool</span></span></code></pre></div>
|
||
<p>we define one type <code>Maybe a</code> that works for all types
|
||
<code>a</code>.</p>
|
||
<p>Here’s our first own parameterized type <code>Described</code>. The
|
||
values of type <code>Described a</code> contain a value of type
|
||
<code>a</code> and a <code>String</code> description.</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">data</span> <span class="dt">Described</span> a <span class="ot">=</span> <span class="dt">Describe</span> a <span class="dt">String</span></span>
|
||
<span id="cb340-2"><a href="#cb340-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb340-3"><a href="#cb340-3" aria-hidden="true" tabindex="-1"></a><span class="ot">getValue ::</span> <span class="dt">Described</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb340-4"><a href="#cb340-4" aria-hidden="true" tabindex="-1"></a>getValue (<span class="dt">Describe</span> x _) <span class="ot">=</span> x</span>
|
||
<span id="cb340-5"><a href="#cb340-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb340-6"><a href="#cb340-6" aria-hidden="true" tabindex="-1"></a><span class="ot">getDescription ::</span> <span class="dt">Described</span> a <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb340-7"><a href="#cb340-7" aria-hidden="true" tabindex="-1"></a>getDescription (<span class="dt">Describe</span> _ desc) <span class="ot">=</span> desc</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Describe</span></span>
|
||
<span id="cb341-2"><a href="#cb341-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Describe</span><span class="ot"> ::</span> a <span class="ot">-></span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Described</span> a</span>
|
||
<span id="cb341-3"><a href="#cb341-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Describe</span> <span class="dt">True</span> <span class="st">"This is true"</span></span>
|
||
<span id="cb341-4"><a href="#cb341-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Describe</span> <span class="dt">True</span> <span class="st">"This is true"</span><span class="ot"> ::</span> <span class="dt">Described</span> <span class="dt">Bool</span></span>
|
||
<span id="cb341-5"><a href="#cb341-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> getValue (<span class="dt">Describe</span> <span class="dv">3</span> <span class="st">"a number"</span>)</span>
|
||
<span id="cb341-6"><a href="#cb341-6" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb341-7"><a href="#cb341-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> getDescription (<span class="dt">Describe</span> <span class="dv">3</span> <span class="st">"a number"</span>)</span>
|
||
<span id="cb341-8"><a href="#cb341-8" aria-hidden="true" tabindex="-1"></a><span class="st">"a number"</span></span></code></pre></div>
|
||
<h3 data-number="5.2.2" id="syntactic-note"><span
|
||
class="header-section-number">5.2.2</span> Syntactic Note</h3>
|
||
<p>In the above definitions, we’ve used <code>a</code> as a type
|
||
variable. However any word that starts with a lower case letter is fine.
|
||
We could have defined <code>Maybe</code> like this:</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">Maybe</span> theType <span class="ot">=</span> <span class="dt">Nothing</span> <span class="op">|</span> <span class="dt">Just</span> theType</span></code></pre></div>
|
||
<p>The rules for Haskell identifiers are:</p>
|
||
<ul>
|
||
<li>Type variables and names for functions and values start lower case
|
||
(e.g. <code>a</code>, <code>map</code>, <code>xs</code>)</li>
|
||
<li>Type names and constructor names start with upper case
|
||
(e.g. <code>Maybe</code>, <code>Just</code>, <code>Card</code>,
|
||
<code>Heart</code>)</li>
|
||
</ul>
|
||
<p>Note that a type and its constructor can have the same name. This is
|
||
very common in Haskell code for types that only have one constructor. In
|
||
this material we try to avoid it to avoid confusion. Here are some
|
||
examples:</p>
|
||
<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><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="cb343-2"><a href="#cb343-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Report</span> <span class="ot">=</span> <span class="dt">Report</span> <span class="dt">Int</span> <span class="dt">String</span> <span class="dt">String</span></span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="dt">Pair</span></span>
|
||
<span id="cb344-2"><a href="#cb344-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Pair</span><span class="ot"> ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Pair</span> a</span></code></pre></div>
|
||
<p>Beware of mixing up types and constructors. Luckily types and
|
||
constructors can never occur in the same context, so you get a nice
|
||
error:</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="dt">Prelude</span><span class="op">></span> <span class="dt">Maybe</span> <span class="co">-- trying to use a type name as a value</span></span>
|
||
<span id="cb345-2"><a href="#cb345-2" 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">1</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb345-3"><a href="#cb345-3" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Data</span> constructor <span class="fu">not</span> <span class="kw">in</span> scope<span class="op">:</span> <span class="dt">Maybe</span></span>
|
||
<span id="cb345-4"><a href="#cb345-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb345-5"><a href="#cb345-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span><span class="ot"> undefined ::</span> <span class="dt">Nothing</span> <span class="co">-- trying to use a constructor as a type</span></span>
|
||
<span id="cb345-6"><a href="#cb345-6" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">2</span><span class="op">:</span><span class="dv">14</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb345-7"><a href="#cb345-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">Not</span> <span class="kw">in</span> scope<span class="op">:</span> <span class="kw">type</span> constructor <span class="fu">or</span> <span class="kw">class</span> ‘<span class="dt">Nothing</span>’</span></code></pre></div>
|
||
<h3 data-number="5.2.3" id="sidenote-multiple-type-parameters"><span
|
||
class="header-section-number">5.2.3</span> Sidenote: Multiple Type
|
||
Parameters</h3>
|
||
<p>Types can have multiple type parameters. The syntax is similar to
|
||
defining functions with many arguments. Here’s the definition of the
|
||
standard <code>Either</code> type:</p>
|
||
<div class="sourceCode" id="cb346"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb346-1"><a href="#cb346-1" 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></code></pre></div>
|
||
<h2 data-number="5.3" id="recursive-types"><span
|
||
class="header-section-number">5.3</span> Recursive Types</h2>
|
||
<p>So far, all of the types we’ve defined have been of constant size. We
|
||
can represent one report or one colour, but how could we represent a
|
||
collection of things? We could use lists of course, but could we define
|
||
a list type ourselves?</p>
|
||
<p>Just like Haskell functions, Haskell data types can be
|
||
<em>recursive</em>. This is no weirder than having an object in Java or
|
||
Python that refers to another object of the same class. This is how you
|
||
define a list of integers:</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">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="cb347-2"><a href="#cb347-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb347-3"><a href="#cb347-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb347-4"><a href="#cb347-4" aria-hidden="true" tabindex="-1"></a><span class="ot">ihead ::</span> <span class="dt">IntList</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb347-5"><a href="#cb347-5" aria-hidden="true" tabindex="-1"></a>ihead (<span class="dt">Node</span> i _) <span class="ot">=</span> i</span>
|
||
<span id="cb347-6"><a href="#cb347-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb347-7"><a href="#cb347-7" aria-hidden="true" tabindex="-1"></a><span class="ot">itail ::</span> <span class="dt">IntList</span> <span class="ot">-></span> <span class="dt">IntList</span></span>
|
||
<span id="cb347-8"><a href="#cb347-8" aria-hidden="true" tabindex="-1"></a>itail (<span class="dt">Node</span> _ t) <span class="ot">=</span> t</span>
|
||
<span id="cb347-9"><a href="#cb347-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb347-10"><a href="#cb347-10" aria-hidden="true" tabindex="-1"></a><span class="ot">ilength ::</span> <span class="dt">IntList</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb347-11"><a href="#cb347-11" aria-hidden="true" tabindex="-1"></a>ilength <span class="dt">Empty</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb347-12"><a href="#cb347-12" aria-hidden="true" tabindex="-1"></a>ilength (<span class="dt">Node</span> _ t) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> ilength t</span></code></pre></div>
|
||
<p>We can use the functions defined above to work with lists of
|
||
integers:</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="dt">Prelude</span><span class="op">></span> ihead (<span class="dt">Node</span> <span class="dv">3</span> (<span class="dt">Node</span> <span class="dv">5</span> (<span class="dt">Node</span> <span class="dv">4</span> <span class="dt">Empty</span>)))</span>
|
||
<span id="cb348-2"><a href="#cb348-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span>
|
||
<span id="cb348-3"><a href="#cb348-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> itail (<span class="dt">Node</span> <span class="dv">3</span> (<span class="dt">Node</span> <span class="dv">5</span> (<span class="dt">Node</span> <span class="dv">4</span> <span class="dt">Empty</span>)))</span>
|
||
<span id="cb348-4"><a href="#cb348-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Node</span> <span class="dv">5</span> (<span class="dt">Node</span> <span class="dv">4</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb348-5"><a href="#cb348-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> ilength (<span class="dt">Node</span> <span class="dv">3</span> (<span class="dt">Node</span> <span class="dv">5</span> (<span class="dt">Node</span> <span class="dv">4</span> <span class="dt">Empty</span>)))</span>
|
||
<span id="cb348-6"><a href="#cb348-6" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span></span></code></pre></div>
|
||
<p>Note that we can’t put values other than <code>Int</code>s inside our
|
||
<code>IntList</code>:</p>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Node</span> <span class="dt">False</span> <span class="dt">Empty</span></span>
|
||
<span id="cb349-2"><a href="#cb349-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb349-3"><a href="#cb349-3" 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">6</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb349-4"><a href="#cb349-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match expected <span class="kw">type</span> ‘<span class="dt">Int</span>’ with actual <span class="kw">type</span> ‘<span class="dt">Bool</span>’</span>
|
||
<span id="cb349-5"><a href="#cb349-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘<span class="dt">Node</span>’, namely ‘<span class="dt">False</span>’</span>
|
||
<span id="cb349-6"><a href="#cb349-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> <span class="dt">Node</span> <span class="dt">False</span> <span class="dt">Empty</span></span>
|
||
<span id="cb349-7"><a href="#cb349-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> <span class="dt">Node</span> <span class="dt">False</span> <span class="dt">Empty</span></span></code></pre></div>
|
||
<p>To be able to put any type of element in our list, let’s do the same
|
||
thing with a type parameter. This is the same as the built in type
|
||
<code>[a]</code>, but with slightly clunkier syntax:</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="kw">data</span> <span class="dt">List</span> a <span class="ot">=</span> <span class="dt">Empty</span> <span class="op">|</span> <span class="dt">Node</span> a (<span class="dt">List</span> a)</span>
|
||
<span id="cb350-2"><a href="#cb350-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
|
||
<p>Note how we need to pass the the type parameter <code>a</code>
|
||
onwards in the recursion. We need to write <code>Node a (List a)</code>
|
||
instead of <code>Node a List</code>. The <code>Node</code> constructor
|
||
has two arguments. The first has type <code>a</code>, and the second has
|
||
type <code>List a</code>. Here are the reimplementations of some
|
||
standard list functions for our <code>List</code> type:</p>
|
||
<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="ot">lhead ::</span> <span class="dt">List</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb351-2"><a href="#cb351-2" aria-hidden="true" tabindex="-1"></a>lhead (<span class="dt">Node</span> h _) <span class="ot">=</span> h</span>
|
||
<span id="cb351-3"><a href="#cb351-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb351-4"><a href="#cb351-4" aria-hidden="true" tabindex="-1"></a><span class="ot">ltail ::</span> <span class="dt">List</span> a <span class="ot">-></span> <span class="dt">List</span> a</span>
|
||
<span id="cb351-5"><a href="#cb351-5" aria-hidden="true" tabindex="-1"></a>ltail (<span class="dt">Node</span> _ t) <span class="ot">=</span> t</span>
|
||
<span id="cb351-6"><a href="#cb351-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb351-7"><a href="#cb351-7" aria-hidden="true" tabindex="-1"></a><span class="ot">lnull ::</span> <span class="dt">List</span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb351-8"><a href="#cb351-8" aria-hidden="true" tabindex="-1"></a>lnull <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb351-9"><a href="#cb351-9" aria-hidden="true" tabindex="-1"></a>lnull _ <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb351-10"><a href="#cb351-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb351-11"><a href="#cb351-11" aria-hidden="true" tabindex="-1"></a><span class="ot">llength ::</span> <span class="dt">List</span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb351-12"><a href="#cb351-12" aria-hidden="true" tabindex="-1"></a>llength <span class="dt">Empty</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb351-13"><a href="#cb351-13" aria-hidden="true" tabindex="-1"></a>llength (<span class="dt">Node</span> _ t) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> llength t</span></code></pre></div>
|
||
<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="dt">Prelude</span><span class="op">></span> lhead (<span class="dt">Node</span> <span class="dt">True</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb352-2"><a href="#cb352-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb352-3"><a href="#cb352-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> ltail (<span class="dt">Node</span> <span class="dt">True</span> (<span class="dt">Node</span> <span class="dt">False</span> <span class="dt">Empty</span>))</span>
|
||
<span id="cb352-4"><a href="#cb352-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Node</span> <span class="dt">False</span> <span class="dt">Empty</span></span>
|
||
<span id="cb352-5"><a href="#cb352-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> lnull <span class="dt">Empty</span></span>
|
||
<span id="cb352-6"><a href="#cb352-6" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<p>Note that just like with normal Haskell lists, we can’t have elements
|
||
of different types in the same list:</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">Prelude</span><span class="op">></span> <span class="dt">Node</span> <span class="dt">True</span> (<span class="dt">Node</span> <span class="st">"foo"</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb353-2"><a href="#cb353-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb353-3"><a href="#cb353-3" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">5</span><span class="op">:</span><span class="dv">12</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb353-4"><a href="#cb353-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">Couldn't</span> match <span class="kw">type</span> ‘[<span class="dt">Char</span>]’ with ‘<span class="dt">Bool</span>’</span>
|
||
<span id="cb353-5"><a href="#cb353-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">Expected</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">List</span> <span class="dt">Bool</span></span>
|
||
<span id="cb353-6"><a href="#cb353-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">Actual</span> <span class="kw">type</span><span class="op">:</span> <span class="dt">List</span> [<span class="dt">Char</span>]</span>
|
||
<span id="cb353-7"><a href="#cb353-7" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the second argument <span class="kw">of</span> ‘<span class="dt">Node</span>’, namely ‘(<span class="dt">Node</span> <span class="st">"foo"</span> <span class="dt">Empty</span>)’</span>
|
||
<span id="cb353-8"><a href="#cb353-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> <span class="dt">Node</span> <span class="dt">True</span> (<span class="dt">Node</span> <span class="st">"foo"</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb353-9"><a href="#cb353-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> <span class="dt">Node</span> <span class="dt">True</span> (<span class="dt">Node</span> <span class="st">"foo"</span> <span class="dt">Empty</span>)</span></code></pre></div>
|
||
<h3 data-number="5.3.1" id="example-growing-a-tree"><span
|
||
class="header-section-number">5.3.1</span> Example: Growing a Tree</h3>
|
||
<p>Just like a list, we can also represent a binary tree:</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="kw">data</span> <span class="dt">Tree</span> a <span class="ot">=</span> <span class="dt">Node</span> a (<span class="dt">Tree</span> a) (<span class="dt">Tree</span> a) <span class="op">|</span> <span class="dt">Empty</span></span></code></pre></div>
|
||
<p>Our tree contains nodes, which contain a value of type <code>a</code>
|
||
and two child trees, and empty trees.</p>
|
||
<p>In case you’re not familiar with binary trees, they’re a data
|
||
structure that’s often used as the basis for other data structures
|
||
(<code>Data.Map</code> is based on trees!). Binary trees are often drawn
|
||
as (upside-down) pictures, like this:</p>
|
||
<p><img src="img/binaryTree.svg" /></p>
|
||
<!--
|
||
```haskell
|
||
0
|
||
/ \
|
||
1 4
|
||
/ \
|
||
2 3
|
||
```
|
||
-->
|
||
<p>The highest node in the tree is called the <em>root</em>
|
||
(<code>0</code> in this case), and the nodes with no children are called
|
||
<code>leaves</code> (<code>2</code>, <code>3</code> and <code>4</code>
|
||
in this case). We can define this tree using our <code>Tree</code> type
|
||
like this:</p>
|
||
<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><span class="ot">example ::</span> <span class="dt">Tree</span> <span class="dt">Int</span></span>
|
||
<span id="cb355-2"><a href="#cb355-2" aria-hidden="true" tabindex="-1"></a>example <span class="ot">=</span> (<span class="dt">Node</span> <span class="dv">0</span> (<span class="dt">Node</span> <span class="dv">1</span> (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb355-3"><a href="#cb355-3" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Node</span> <span class="dv">3</span> <span class="dt">Empty</span> <span class="dt">Empty</span>))</span>
|
||
<span id="cb355-4"><a href="#cb355-4" aria-hidden="true" tabindex="-1"></a> (<span class="dt">Node</span> <span class="dv">4</span> <span class="dt">Empty</span> <span class="dt">Empty</span>))</span></code></pre></div>
|
||
<p>The height of a binary tree is length of the longest path from the
|
||
root to a leaf. In Haskell terms, it’s how many nested levels of
|
||
<code>Node</code> constructors you need to build the tree. The height of
|
||
our example tree is 3. Here’s a function that computes the height of a
|
||
tree:</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><span class="ot">treeHeight ::</span> <span class="dt">Tree</span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb356-2"><a href="#cb356-2" aria-hidden="true" tabindex="-1"></a>treeHeight <span class="dt">Empty</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb356-3"><a href="#cb356-3" aria-hidden="true" tabindex="-1"></a>treeHeight (<span class="dt">Node</span> _ l r) <span class="ot">=</span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> (treeHeight l) (treeHeight r)</span></code></pre></div>
|
||
<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>treeHeight <span class="dt">Empty</span> <span class="op">==></span> <span class="dv">0</span></span>
|
||
<span id="cb357-2"><a href="#cb357-2" aria-hidden="true" tabindex="-1"></a>treeHeight (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>)</span>
|
||
<span id="cb357-3"><a href="#cb357-3" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> (treeHeight <span class="dt">Empty</span>) (treeHeight <span class="dt">Empty</span>)</span>
|
||
<span id="cb357-4"><a href="#cb357-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> <span class="dv">0</span> <span class="dv">0</span></span>
|
||
<span id="cb357-5"><a href="#cb357-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb357-6"><a href="#cb357-6" aria-hidden="true" tabindex="-1"></a>treeHeight (<span class="dt">Node</span> <span class="dv">1</span> <span class="dt">Empty</span> (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>))</span>
|
||
<span id="cb357-7"><a href="#cb357-7" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> (treeHeight <span class="dt">Empty</span>) (treeHeight (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>))</span>
|
||
<span id="cb357-8"><a href="#cb357-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> <span class="dv">0</span> <span class="dv">1</span></span>
|
||
<span id="cb357-9"><a href="#cb357-9" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">2</span></span>
|
||
<span id="cb357-10"><a href="#cb357-10" aria-hidden="true" tabindex="-1"></a>treeHeight (<span class="dt">Node</span> <span class="dv">0</span> (<span class="dt">Node</span> <span class="dv">1</span> <span class="dt">Empty</span> (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>)) <span class="dt">Empty</span>)</span>
|
||
<span id="cb357-11"><a href="#cb357-11" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> (treeHeight (<span class="dt">Node</span> <span class="dv">1</span> <span class="dt">Empty</span> (<span class="dt">Node</span> <span class="dv">2</span> <span class="dt">Empty</span> <span class="dt">Empty</span>))) (treeHeight <span class="dt">Empty</span>)</span>
|
||
<span id="cb357-12"><a href="#cb357-12" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">1</span> <span class="op">+</span> <span class="fu">max</span> <span class="dv">2</span> <span class="dv">0</span></span>
|
||
<span id="cb357-13"><a href="#cb357-13" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<p>In case you’re familiar with <em>binary search trees</em>, here are
|
||
the definitions of the lookup and insert opertions for a binary search
|
||
tree. If you don’t know what I’m talking about, you don’t need to
|
||
understand this.</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="fu">lookup</span><span class="ot"> ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Tree</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb358-2"><a href="#cb358-2" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> x <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb358-3"><a href="#cb358-3" aria-hidden="true" tabindex="-1"></a><span class="fu">lookup</span> x (<span class="dt">Node</span> y l r)</span>
|
||
<span id="cb358-4"><a href="#cb358-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op"><</span> y <span class="ot">=</span> <span class="fu">lookup</span> x l</span>
|
||
<span id="cb358-5"><a href="#cb358-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op">></span> y <span class="ot">=</span> <span class="fu">lookup</span> x r</span>
|
||
<span id="cb358-6"><a href="#cb358-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb358-7"><a href="#cb358-7" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb358-8"><a href="#cb358-8" aria-hidden="true" tabindex="-1"></a><span class="ot">insert ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Tree</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Tree</span> <span class="dt">Int</span></span>
|
||
<span id="cb358-9"><a href="#cb358-9" aria-hidden="true" tabindex="-1"></a>insert x <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span></span>
|
||
<span id="cb358-10"><a href="#cb358-10" aria-hidden="true" tabindex="-1"></a>insert x (<span class="dt">Node</span> y l r)</span>
|
||
<span id="cb358-11"><a href="#cb358-11" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op"><</span> y <span class="ot">=</span> <span class="dt">Node</span> y (insert x l) r</span>
|
||
<span id="cb358-12"><a href="#cb358-12" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op">></span> y <span class="ot">=</span> <span class="dt">Node</span> y l (insert x r)</span>
|
||
<span id="cb358-13"><a href="#cb358-13" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Node</span> y l r</span></code></pre></div>
|
||
<h2 data-number="5.4" id="record-syntax"><span
|
||
class="header-section-number">5.4</span> Record Syntax</h2>
|
||
<p>If some fields need to be accessed often, it can be convenient to
|
||
have helper functions for reading those fields. For instance, the type
|
||
<code>Person</code> might have multiple fields:</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="kw">data</span> <span class="dt">Person</span> <span class="ot">=</span> <span class="dt">MkPerson</span> <span class="dt">String</span> <span class="dt">Int</span> <span class="dt">String</span> <span class="dt">String</span> <span class="dt">String</span> <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
|
||
<p>A list of persons might look like the following:</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="ot">people ::</span> [<span class="dt">Person</span>]</span>
|
||
<span id="cb360-2"><a href="#cb360-2" aria-hidden="true" tabindex="-1"></a>people <span class="ot">=</span> [ <span class="dt">MkPerson</span> <span class="st">"Jane Doe"</span> <span class="dv">21</span> <span class="st">"Houston"</span> <span class="st">"Texas"</span> <span class="st">"Engineer"</span></span>
|
||
<span id="cb360-3"><a href="#cb360-3" aria-hidden="true" tabindex="-1"></a> , <span class="dt">MkPerson</span> <span class="st">"Maija Meikäläinen"</span> <span class="dv">35</span> <span class="st">"Rovaniemi"</span> <span class="st">"Finland"</span> <span class="st">"Engineer"</span></span>
|
||
<span id="cb360-4"><a href="#cb360-4" aria-hidden="true" tabindex="-1"></a> , <span class="dt">MkPerson</span> <span class="st">"Mauno Mutikainen"</span> <span class="dv">27</span> <span class="st">"Turku"</span> <span class="st">"Finland"</span> <span class="st">"Mathematician"</span></span>
|
||
<span id="cb360-5"><a href="#cb360-5" aria-hidden="true" tabindex="-1"></a> ]</span></code></pre></div>
|
||
<p>Suppose that we need to find all engineers from Finland:</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">query ::</span> [<span class="dt">Person</span>] <span class="ot">-></span> [<span class="dt">Person</span>]</span>
|
||
<span id="cb361-2"><a href="#cb361-2" aria-hidden="true" tabindex="-1"></a>query [] <span class="ot">=</span> []</span>
|
||
<span id="cb361-3"><a href="#cb361-3" aria-hidden="true" tabindex="-1"></a>query ((<span class="dt">MkPerson</span> name age town state profession)<span class="op">:</span>xs)</span>
|
||
<span id="cb361-4"><a href="#cb361-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> state <span class="op">==</span> <span class="st">"Finland"</span> <span class="op">&&</span> profession <span class="op">==</span> <span class="st">"Engineer"</span> <span class="ot">=</span></span>
|
||
<span id="cb361-5"><a href="#cb361-5" aria-hidden="true" tabindex="-1"></a> (<span class="dt">MkPerson</span> name age town state profession) <span class="op">:</span> query xs</span>
|
||
<span id="cb361-6"><a href="#cb361-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> query xs</span></code></pre></div>
|
||
<p>Thus,</p>
|
||
<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>query people <span class="op">==></span> [<span class="dt">MkPerson</span> <span class="st">"Maija Meikäläinen"</span> <span class="dv">35</span> <span class="st">"Rovaniemi"</span> <span class="st">"Finland"</span> <span class="st">"Engineer"</span>]</span></code></pre></div>
|
||
<p>Note that the types of the fields give little information on what is
|
||
the intended content in those fields. We need to remember in all places
|
||
in the code that <code>town</code> goes before <code>state</code> and
|
||
not vice versa.</p>
|
||
<p>Haskell has a feature called <em>record syntax</em> that is helpful
|
||
in these kinds of cases. The datatype <code>Person</code> can be defined
|
||
as a record:</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">data</span> <span class="dt">Person</span> <span class="ot">=</span> <span class="dt">MkPerson</span> {<span class="ot"> name ::</span> <span class="dt">String</span>,<span class="ot"> age ::</span> <span class="dt">Int</span>,<span class="ot"> town ::</span> <span class="dt">String</span>,<span class="ot"> state ::</span> <span class="dt">String</span>,<span class="ot"> profession ::</span> <span class="dt">String</span>}</span>
|
||
<span id="cb363-2"><a href="#cb363-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span></code></pre></div>
|
||
<p>We can still define values of <code>Person</code> normally, but the
|
||
<code>Show</code> instance prints the field names for us:</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="dt">Prelude</span><span class="op">></span> <span class="dt">MkPerson</span> <span class="st">"Jane Doe"</span> <span class="dv">21</span> <span class="st">"Houston"</span> <span class="st">"Texas"</span> <span class="st">"Engineer"</span></span>
|
||
<span id="cb364-2"><a href="#cb364-2" aria-hidden="true" tabindex="-1"></a><span class="dt">MkPerson</span> {name <span class="ot">=</span> <span class="st">"Jane Doe"</span>, age <span class="ot">=</span> <span class="dv">21</span>, town <span class="ot">=</span> <span class="st">"Houston"</span>, state <span class="ot">=</span> <span class="st">"Texas"</span>, profession <span class="ot">=</span> <span class="st">"Engineer"</span>}</span></code></pre></div>
|
||
<p>However, we can also define values using record syntax. Note how the
|
||
fields don’t need to be in any specific order now that they have
|
||
names.</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><span class="dt">Prelude</span><span class="op">></span> <span class="dt">MkPerson</span> {name <span class="ot">=</span> <span class="st">"Jane Doe"</span>, town <span class="ot">=</span> <span class="st">"Houston"</span>, profession <span class="ot">=</span> <span class="st">"Engineer"</span>, state <span class="ot">=</span> <span class="st">"Texas"</span>, age <span class="ot">=</span> <span class="dv">21</span>}</span>
|
||
<span id="cb365-2"><a href="#cb365-2" aria-hidden="true" tabindex="-1"></a><span class="dt">MkPerson</span> {name <span class="ot">=</span> <span class="st">"Jane Doe"</span>, age <span class="ot">=</span> <span class="dv">21</span>, town <span class="ot">=</span> <span class="st">"Houston"</span>, state <span class="ot">=</span> <span class="st">"Texas"</span>, profession <span class="ot">=</span> <span class="st">"Engineer"</span>}</span></code></pre></div>
|
||
<p>Most importantly, We get <em>accessor functions</em> for the fields
|
||
for free:</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t profession</span>
|
||
<span id="cb366-2"><a href="#cb366-2" aria-hidden="true" tabindex="-1"></a><span class="ot">profession ::</span> <span class="dt">Person</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb366-3"><a href="#cb366-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> profession (<span class="dt">MkPerson</span> <span class="st">"Jane Doe"</span> <span class="dv">21</span> <span class="st">"Houston"</span> <span class="st">"Texas"</span> <span class="st">"Engineer"</span>)</span>
|
||
<span id="cb366-4"><a href="#cb366-4" aria-hidden="true" tabindex="-1"></a><span class="st">"Engineer"</span></span></code></pre></div>
|
||
<p>We can now rewrite the query function using these accessor
|
||
functions:</p>
|
||
<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><span class="ot">query ::</span> [<span class="dt">Person</span>] <span class="ot">-></span> [<span class="dt">Person</span>]</span>
|
||
<span id="cb367-2"><a href="#cb367-2" aria-hidden="true" tabindex="-1"></a>query [] <span class="ot">=</span> []</span>
|
||
<span id="cb367-3"><a href="#cb367-3" aria-hidden="true" tabindex="-1"></a>query (x<span class="op">:</span>xs)</span>
|
||
<span id="cb367-4"><a href="#cb367-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> state x <span class="op">==</span> <span class="st">"Finland"</span> <span class="op">&&</span> profession x <span class="op">==</span> <span class="st">"Engineer"</span> <span class="ot">=</span></span>
|
||
<span id="cb367-5"><a href="#cb367-5" aria-hidden="true" tabindex="-1"></a> x <span class="op">:</span> query xs</span>
|
||
<span id="cb367-6"><a href="#cb367-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> query xs</span></code></pre></div>
|
||
<p>You’ll probably agree that the code looks more pleasant now.</p>
|
||
<h2 data-number="5.5" id="algebraic-datatypes-summary"><span
|
||
class="header-section-number">5.5</span> Algebraic Datatypes:
|
||
Summary</h2>
|
||
<ul>
|
||
<li>Types are defined like this</li>
|
||
</ul>
|
||
<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">data</span> <span class="dt">TypeName</span> <span class="ot">=</span> <span class="dt">ConstructorName</span> <span class="dt">FieldType</span> <span class="dt">FieldType2</span> <span class="op">|</span> <span class="dt">AnotherConstructor</span> <span class="dt">FieldType3</span> <span class="op">|</span> <span class="dt">OneMoreCons</span></span></code></pre></div>
|
||
<ul>
|
||
<li>… or like this if we’re using type variables</li>
|
||
</ul>
|
||
<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><span class="kw">data</span> <span class="dt">TypeName</span> variable <span class="ot">=</span> <span class="dt">Cons1</span> variable <span class="dt">Type1</span> <span class="op">|</span> <span class="dt">Cons2</span> <span class="dt">Type2</span> variable</span></code></pre></div>
|
||
<ul>
|
||
<li>You can have one or more constructors</li>
|
||
<li>Each constructor can have zero or more fields</li>
|
||
<li>Constructors start with upper case, type variables with lower
|
||
case</li>
|
||
<li>Values are handled with pattern matching:</li>
|
||
</ul>
|
||
<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>foo (<span class="dt">ConstructorName</span> a b) <span class="ot">=</span> a<span class="op">+</span>b</span>
|
||
<span id="cb370-2"><a href="#cb370-2" aria-hidden="true" tabindex="-1"></a>foo (<span class="dt">AnotherConstructor</span> _) <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb370-3"><a href="#cb370-3" aria-hidden="true" tabindex="-1"></a>foo <span class="dt">OneMoreCons</span> <span class="ot">=</span> <span class="dv">7</span></span></code></pre></div>
|
||
<ul>
|
||
<li>Constructors are just functions:</li>
|
||
</ul>
|
||
<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="dt">ConstructorName</span><span class="ot"> ::</span> <span class="dt">FieldType</span> <span class="ot">-></span> <span class="dt">FieldType2</span> <span class="ot">-></span> <span class="dt">TypeName</span></span>
|
||
<span id="cb371-2"><a href="#cb371-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Cons1</span><span class="ot"> ::</span> a <span class="ot">-></span> <span class="dt">Type1</span> <span class="ot">-></span> <span class="dt">TypeName</span> a</span></code></pre></div>
|
||
<ul>
|
||
<li>You can also define datatypes using record syntax:</li>
|
||
</ul>
|
||
<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="kw">data</span> <span class="dt">TypeName</span> <span class="ot">=</span> <span class="dt">Constructor</span> {<span class="ot"> field1 ::</span> <span class="dt">Field1Type</span>,<span class="ot"> field2 ::</span> <span class="dt">Field2Type</span> }</span></code></pre></div>
|
||
<p>This gives you accessor functions like
|
||
<code>field1 :: TypeName -> Field1Type</code> for free.</p>
|
||
<h2 data-number="5.6" id="sidenote-other-ways-of-defining-types"><span
|
||
class="header-section-number">5.6</span> Sidenote: Other Ways of
|
||
Defining Types</h2>
|
||
<p>In addition to the <code>data</code> keyword, there are two
|
||
additional ways of defining types in Haskell.</p>
|
||
<p>The <code>newtype</code> keyword works like <code>data</code>, but
|
||
you can only have a single constructor with a single field. It’s
|
||
sometimes wise to use <code>newtype</code> for performance reasons, but
|
||
we’ll get back to those in part 2.</p>
|
||
<p>The <code>type</code> keyword introduces a <em>type alias</em>. Type
|
||
aliases don’t affect type checking, they just offer a shorthand for
|
||
writing types. For example the familiar <code>String</code> type is an
|
||
alias for <code>[Char]</code>:</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="kw">type</span> <span class="dt">String</span> <span class="ot">=</span> [<span class="dt">Char</span>]</span></code></pre></div>
|
||
<p>This means that whenever the compiler reads <code>String</code>, it
|
||
just immediately replaces it with <code>[Char]</code>. Type aliases seem
|
||
useful, but they can easily make reading type errors harder.</p>
|
||
<h2 data-number="5.7" id="how-do-algebraic-datatypes-work"><span
|
||
class="header-section-number">5.7</span> How Do Algebraic Datatypes
|
||
Work?</h2>
|
||
<p>Remember how lists were represented in memory as linked lists? Let’s
|
||
look in more detail at what algebraic datatypes look like in memory.</p>
|
||
<p>Haskell data forms <em>directed graphs</em> in memory. Every
|
||
constructor is a node, every field is an edge. Names (of variables) are
|
||
pointers into this graph. Different names can <em>share</em> parts of
|
||
the structure. Here’s an example with lists. Note how the last two
|
||
elements of <code>x</code> are shared with <code>y</code> and
|
||
<code>z</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="kw">let</span> x <span class="ot">=</span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb374-2"><a href="#cb374-2" aria-hidden="true" tabindex="-1"></a> y <span class="ot">=</span> <span class="fu">drop</span> <span class="dv">2</span> x</span>
|
||
<span id="cb374-3"><a href="#cb374-3" aria-hidden="true" tabindex="-1"></a> z <span class="ot">=</span> <span class="dv">5</span><span class="op">:</span>y</span></code></pre></div>
|
||
<p><img src="img/DAG1.svg" /></p>
|
||
<!--
|
||
```haskell
|
||
code memory
|
||
x y
|
||
| |
|
||
v v
|
||
let x = [1,2,3,4] (1:) -> (2:) -> (3:) -> (4:) -> []
|
||
y = drop 2 x ^
|
||
z = 5:y |
|
||
z -> (5:) --+
|
||
```
|
||
-->
|
||
<p>What happens when you make a new version of a datastructure is called
|
||
<em>path copying</em>. Since Haskell data is immutable, the changed
|
||
parts of the datastructure get copied, while the unchanged parts can be
|
||
shared between the old and new versions.</p>
|
||
<p>Consider the definition of <code>++</code>:</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="op">++</span> ys <span class="ot">=</span> ys</span>
|
||
<span id="cb375-2"><a href="#cb375-2" aria-hidden="true" tabindex="-1"></a>(x<span class="op">:</span>xs) <span class="op">++</span> ys <span class="ot">=</span> x<span class="op">:</span>(xs <span class="op">++</span> ys)</span></code></pre></div>
|
||
<p>We are making a copy of the first argument while we walk it. For
|
||
every <code>:</code> constructor in the first input list, we are
|
||
creating a new <code>:</code> constructor in the output list. The second
|
||
argument can be shared. It is not used at all in the recursion.
|
||
Visually:</p>
|
||
<p><img src="img/DAG2.svg" /></p>
|
||
<!--
|
||
```haskell
|
||
xs -> (1:) -> (2:) -> (3:) -> []
|
||
|
||
ys -> (5:) -> (6:) -> []
|
||
^
|
||
|
|
||
xs ++ ys -> (1:) -> (2:) -> (3:) --+
|
||
```
|
||
-->
|
||
<p>One more way to think about it is this: we want to change the
|
||
<code>tail</code> pointer of the list element <code>(3:)</code>. That
|
||
means we need to make a new <code>(3:)</code>. However the
|
||
<code>(2:)</code> points to the <code>(3:)</code> so we need a new copy
|
||
of the <code>(2:)</code> as well. Likewise for <code>(1:)</code>.</p>
|
||
<p>The graphs that we get when working with lists are fairly simple. As
|
||
a more involved example, here is what happens in memory when we run the
|
||
binary tree insertion example from earlier in this lecture.</p>
|
||
<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><span class="ot">insert ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Tree</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Tree</span> <span class="dt">Int</span></span>
|
||
<span id="cb376-2"><a href="#cb376-2" aria-hidden="true" tabindex="-1"></a>insert x <span class="dt">Empty</span> <span class="ot">=</span> <span class="dt">Node</span> x <span class="dt">Empty</span> <span class="dt">Empty</span></span>
|
||
<span id="cb376-3"><a href="#cb376-3" aria-hidden="true" tabindex="-1"></a>insert x (<span class="dt">Node</span> y l r)</span>
|
||
<span id="cb376-4"><a href="#cb376-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op"><</span> y <span class="ot">=</span> <span class="dt">Node</span> y (insert x l) r</span>
|
||
<span id="cb376-5"><a href="#cb376-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op">></span> y <span class="ot">=</span> <span class="dt">Node</span> y l (insert x r)</span>
|
||
<span id="cb376-6"><a href="#cb376-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">Node</span> y l r</span></code></pre></div>
|
||
<p><img src="img/DAG3.svg" /> <!--
|
||
```haskell
|
||
t insert 6 t
|
||
| |
|
||
Node 5 Node 5
|
||
/______\__________/ \
|
||
// \ \
|
||
Node 3 Node 7 Node 7
|
||
/ \ / \ / \
|
||
Empty Node 4 Empty Empty Node 6 Empty
|
||
/ \ / \
|
||
Empty Empty Empty Empty
|
||
```
|
||
--></p>
|
||
<p>Note how the old and the new tree share the subtree with 3 and 4
|
||
since it wasn’t changed, but the node 7 that was “changed” and all nodes
|
||
above it get copied.</p>
|
||
<h2 data-number="5.8" id="quiz-4"><span
|
||
class="header-section-number">5.8</span> Quiz</h2>
|
||
<p>Why can’t we <code>map Nothing</code>?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
Because <code>Nothing</code> doesn’t take arguments
|
||
</li>
|
||
<li>
|
||
Because <code>Nothing</code> returns nothing
|
||
</li>
|
||
<li>
|
||
Because <code>Nothing</code> is a constructor.
|
||
</li>
|
||
</ol>
|
||
<p>If we define
|
||
<code>data Boing = Frick String Boing (Int -> Bool)</code>, what is
|
||
the type of <code>Frick</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Boing</code>
|
||
</li>
|
||
<li>
|
||
<code>String -> Boing -> Int -> Bool -> Boing</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>String -> Boing -> (Int -> Bool) -> Boing</code>
|
||
</li>
|
||
</ol>
|
||
<p>If we define
|
||
<code>data ThreeLists a b c = ThreeLists [a] [b] [c]</code>, what is the
|
||
type of the constructor <code>ThreeLists</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>[a] -> [b] -> [c] -> ThreeLists</code>
|
||
</li>
|
||
<li>
|
||
<code>a -> b -> c -> ThreeLists a b c</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>[a] -> [b] -> [c] -> ThreeLists a b c</code>
|
||
</li>
|
||
<li>
|
||
<code>[a] -> [b] -> [c] -> ThreeLists [a] [b] [c]</code>
|
||
</li>
|
||
</ol>
|
||
<p>If we define
|
||
<code>data TwoLists a b = TwoList {aList :: [a], bList :: [b]}</code>,
|
||
what is the type of the function <code>aList</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>aList</code> is not a function, it is a field
|
||
</li>
|
||
<li class="correct">
|
||
<code>TwoLists a b -> [a]</code>
|
||
</li>
|
||
<li>
|
||
<code>[a] -> TwoLists a b</code>
|
||
</li>
|
||
<li>
|
||
<code>[a]</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="5.9" id="exercises-4"><span
|
||
class="header-section-number">5.9</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set5a.hs">Set5a</a>:
|
||
using and defining algebraic datatypes</li>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set5b.hs">Set5b</a>:
|
||
playing with binary trees</li>
|
||
</ul>
|
||
<h1 data-number="6" id="lecture-6-working-class-hero"><span
|
||
class="header-section-number">6</span> Lecture 6: Working Class
|
||
Hero</h1>
|
||
<p>We’ve seen class constraints like <code>Eq a =></code> in types.
|
||
We know how to use existing classes with existing types. But how do we
|
||
use existing classes with our own types? How can we define our own
|
||
classes?</p>
|
||
<p>Here’s how to make your own type a member of the <code>Eq</code>
|
||
class:</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="kw">data</span> <span class="dt">Color</span> <span class="ot">=</span> <span class="dt">Black</span> <span class="op">|</span> <span class="dt">White</span></span>
|
||
<span id="cb377-2"><a href="#cb377-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb377-3"><a href="#cb377-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Eq</span> <span class="dt">Color</span> <span class="kw">where</span></span>
|
||
<span id="cb377-4"><a href="#cb377-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">Black</span> <span class="op">==</span> <span class="dt">Black</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb377-5"><a href="#cb377-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">White</span> <span class="op">==</span> <span class="dt">White</span> <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb377-6"><a href="#cb377-6" aria-hidden="true" tabindex="-1"></a> _ <span class="op">==</span> _ <span class="ot">=</span> <span class="dt">False</span></span></code></pre></div>
|
||
<p>A class instance is an <code>instance</code> block that contains
|
||
definitions for the functions in that class. Here we define how
|
||
<code>==</code> works on <code>Color</code>.</p>
|
||
<h2 data-number="6.1" id="syntax-of-classes-and-instances"><span
|
||
class="header-section-number">6.1</span> Syntax of Classes and
|
||
Instances</h2>
|
||
<p>A type class is defined using <code>class</code> syntax. The
|
||
functions in the class are given types. Here’s a class <code>Size</code>
|
||
that contains one function, <code>size</code>:</p>
|
||
<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="kw">class</span> <span class="dt">Size</span> a <span class="kw">where</span></span>
|
||
<span id="cb378-2"><a href="#cb378-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> size ::</span> a <span class="ot">-></span> <span class="dt">Int</span></span></code></pre></div>
|
||
<p>Instances of a class are defined with <code>instance</code> syntax
|
||
we’ve just seen. Here is how we make <code>Int</code> and
|
||
<code>[a]</code> members of the <code>Size</code> 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">instance</span> <span class="dt">Size</span> <span class="dt">Int</span> <span class="kw">where</span></span>
|
||
<span id="cb379-2"><a href="#cb379-2" aria-hidden="true" tabindex="-1"></a> size x <span class="ot">=</span> <span class="fu">abs</span> x</span>
|
||
<span id="cb379-3"><a href="#cb379-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb379-4"><a href="#cb379-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Size</span> [a] <span class="kw">where</span></span>
|
||
<span id="cb379-5"><a href="#cb379-5" aria-hidden="true" tabindex="-1"></a> size xs <span class="ot">=</span> <span class="fu">length</span> xs</span></code></pre></div>
|
||
<p>Our class <code>Size</code> behaves just like existing type classes.
|
||
We can use <code>size</code> anywhere where a function can be used, and
|
||
Haskell can infer types with <code>Size</code> constraints for us:</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="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t size</span>
|
||
<span id="cb380-2"><a href="#cb380-2" aria-hidden="true" tabindex="-1"></a><span class="ot">size ::</span> <span class="dt">Size</span> a <span class="ot">=></span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb380-3"><a href="#cb380-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> size [<span class="dt">True</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb380-4"><a href="#cb380-4" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span>
|
||
<span id="cb380-5"><a href="#cb380-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> sizeBoth a b <span class="ot">=</span> [size a, size b]</span>
|
||
<span id="cb380-6"><a href="#cb380-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t sizeBoth</span>
|
||
<span id="cb380-7"><a href="#cb380-7" aria-hidden="true" tabindex="-1"></a><span class="ot">sizeBoth ::</span> (<span class="dt">Size</span> a1, <span class="dt">Size</span> a2) <span class="ot">=></span> a1 <span class="ot">-></span> a2 <span class="ot">-></span> [<span class="dt">Int</span>]</span></code></pre></div>
|
||
<p>A class can contain multiple functions, and even constants. Here we
|
||
define a new version of the <code>Size</code> class with more
|
||
content.</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">class</span> <span class="dt">Size</span> a <span class="kw">where</span></span>
|
||
<span id="cb381-2"><a href="#cb381-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> empty ::</span> a</span>
|
||
<span id="cb381-3"><a href="#cb381-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="cb381-4"><a href="#cb381-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> sameSize ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb381-5"><a href="#cb381-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-6"><a href="#cb381-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Size</span> (<span class="dt">Maybe</span> a) <span class="kw">where</span></span>
|
||
<span id="cb381-7"><a href="#cb381-7" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb381-8"><a href="#cb381-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-9"><a href="#cb381-9" aria-hidden="true" tabindex="-1"></a> size <span class="dt">Nothing</span> <span class="ot">=</span> <span class="dv">0</span></span>
|
||
<span id="cb381-10"><a href="#cb381-10" aria-hidden="true" tabindex="-1"></a> size (<span class="dt">Just</span> a) <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb381-11"><a href="#cb381-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-12"><a href="#cb381-12" aria-hidden="true" tabindex="-1"></a> sameSize x y <span class="ot">=</span> size x <span class="op">==</span> size y</span>
|
||
<span id="cb381-13"><a href="#cb381-13" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb381-14"><a href="#cb381-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Size</span> [a] <span class="kw">where</span></span>
|
||
<span id="cb381-15"><a href="#cb381-15" aria-hidden="true" tabindex="-1"></a> empty <span class="ot">=</span> []</span>
|
||
<span id="cb381-16"><a href="#cb381-16" aria-hidden="true" tabindex="-1"></a> size xs <span class="ot">=</span> <span class="fu">length</span> xs</span>
|
||
<span id="cb381-17"><a href="#cb381-17" aria-hidden="true" tabindex="-1"></a> sameSize x y <span class="ot">=</span> size x <span class="op">==</span> size y</span></code></pre></div>
|
||
<h2 data-number="6.2" id="default-implementations"><span
|
||
class="header-section-number">6.2</span> Default Implementations</h2>
|
||
<p>Did you notice how in the previous example we gave
|
||
<code>sameSize</code> the same definition in both instances? This is a
|
||
very common occurrence, and it’s why Haskell classes can have
|
||
<em>default implementations</em>. As a first example, here’s an
|
||
<code>Example</code> type class for giving example values of types.</p>
|
||
<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><span class="kw">class</span> <span class="dt">Example</span> a <span class="kw">where</span></span>
|
||
<span id="cb382-2"><a href="#cb382-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> example ::</span> a <span class="co">-- the main example for the type `a`</span></span>
|
||
<span id="cb382-3"><a href="#cb382-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> examples ::</span> [a] <span class="co">-- a short list of examples</span></span>
|
||
<span id="cb382-4"><a href="#cb382-4" aria-hidden="true" tabindex="-1"></a> examples <span class="ot">=</span> [example] <span class="co">-- ...defaulting to just the main example</span></span>
|
||
<span id="cb382-5"><a href="#cb382-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb382-6"><a href="#cb382-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Example</span> <span class="dt">Int</span> <span class="kw">where</span></span>
|
||
<span id="cb382-7"><a href="#cb382-7" aria-hidden="true" tabindex="-1"></a> example <span class="ot">=</span> <span class="dv">1</span></span>
|
||
<span id="cb382-8"><a href="#cb382-8" aria-hidden="true" tabindex="-1"></a> examples <span class="ot">=</span> [<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</span>
|
||
<span id="cb382-9"><a href="#cb382-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb382-10"><a href="#cb382-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Example</span> <span class="dt">Bool</span> <span class="kw">where</span></span>
|
||
<span id="cb382-11"><a href="#cb382-11" aria-hidden="true" tabindex="-1"></a> example <span class="ot">=</span> <span class="dt">True</span></span></code></pre></div>
|
||
<p>Here’s how <code>Example</code> works. Note how the default
|
||
implementation of <code>examples</code> got used in the
|
||
<code>Bool</code> case but not in the <code>Int</code> case. Also note
|
||
the need for explicit type signatures to tell GHCi which instance we’re
|
||
interested in. Without them, we would get an “Ambiguous type variable”
|
||
error.</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="dt">Prelude</span><span class="op">></span><span class="ot"> example ::</span> <span class="dt">Bool</span></span>
|
||
<span id="cb383-2"><a href="#cb383-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb383-3"><a href="#cb383-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span><span class="ot"> example ::</span> <span class="dt">Int</span></span>
|
||
<span id="cb383-4"><a href="#cb383-4" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span></span>
|
||
<span id="cb383-5"><a href="#cb383-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span><span class="ot"> examples ::</span> [<span class="dt">Bool</span>]</span>
|
||
<span id="cb383-6"><a href="#cb383-6" aria-hidden="true" tabindex="-1"></a>[<span class="dt">True</span>]</span>
|
||
<span id="cb383-7"><a href="#cb383-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span><span class="ot"> examples ::</span> [<span class="dt">Int</span>]</span>
|
||
<span id="cb383-8"><a href="#cb383-8" aria-hidden="true" tabindex="-1"></a>[<span class="dv">0</span>,<span class="dv">1</span>,<span class="dv">2</span>]</span></code></pre></div>
|
||
<p>The standard type classes use lots of default implementations to make
|
||
implementing the classes easy. Here is the standard definitions for
|
||
<code>Eq</code> (formatted for readability).</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">class</span> <span class="dt">Eq</span> a <span class="kw">where</span></span>
|
||
<span id="cb384-2"><a href="#cb384-2" 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>
|
||
<span id="cb384-3"><a href="#cb384-3" aria-hidden="true" tabindex="-1"></a> x <span class="op">==</span> y <span class="ot">=</span> <span class="fu">not</span> (x <span class="op">/=</span> y)</span>
|
||
<span id="cb384-4"><a href="#cb384-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb384-5"><a href="#cb384-5" 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>
|
||
<span id="cb384-6"><a href="#cb384-6" aria-hidden="true" tabindex="-1"></a> x <span class="op">/=</span> y <span class="ot">=</span> <span class="fu">not</span> (x <span class="op">==</span> y)</span></code></pre></div>
|
||
<p>Note how both operations have a default implementation in terms of
|
||
the other. This means we could define an <code>Eq</code> instance with
|
||
no content at all, but the resulting functions would just recurse
|
||
forever. In practice, we want to define at least one of <code>==</code>
|
||
and <code>/=</code>.</p>
|
||
<p>When there are lots of default implementations, it can be hard to
|
||
know which functions you need to implement yourself. For this reason
|
||
class documentation usually mentions the <em>minimal complete
|
||
definition</em>. For <code>Eq</code>, <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Prelude.html#t:Eq">the
|
||
docs say</a> “Minimal complete definition: either == or /=.”</p>
|
||
<p>Let’s look at <code>Ord</code> next. <code>Ord</code> has 7
|
||
operations, all with default implementations in terms of each other. By
|
||
the way, note the quirky way of defining multiple type signatures at
|
||
once. It’s okay, it’s a feature of Haskell, this is how <code>Ord</code>
|
||
is defined in <a
|
||
href="https://www.haskell.org/onlinereport/haskell2010/haskellch6.html#x13-1270006.3">the
|
||
standard</a>. (We’ll get back to what the <code>(Eq a) =></code> part
|
||
means soon.)</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="kw">class</span> (<span class="dt">Eq</span> a) <span class="ot">=></span> <span class="dt">Ord</span> a <span class="kw">where</span></span>
|
||
<span id="cb385-2"><a href="#cb385-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> compare ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Ordering</span></span>
|
||
<span id="cb385-3"><a href="#cb385-3" aria-hidden="true" tabindex="-1"></a> (<span class="op"><</span>), (<span class="op"><=</span>), (<span class="op">>=</span>),<span class="ot"> (>) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb385-4"><a href="#cb385-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">max</span>,<span class="ot"> min ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb385-5"><a href="#cb385-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb385-6"><a href="#cb385-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">compare</span> x y <span class="op">|</span> x <span class="op">==</span> y <span class="ot">=</span> <span class="dt">EQ</span></span>
|
||
<span id="cb385-7"><a href="#cb385-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> x <span class="op"><=</span> y <span class="ot">=</span> <span class="dt">LT</span></span>
|
||
<span id="cb385-8"><a href="#cb385-8" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> <span class="dt">GT</span></span>
|
||
<span id="cb385-9"><a href="#cb385-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb385-10"><a href="#cb385-10" aria-hidden="true" tabindex="-1"></a> x <span class="op"><=</span> y <span class="ot">=</span> <span class="fu">compare</span> x y <span class="op">/=</span> <span class="dt">GT</span></span>
|
||
<span id="cb385-11"><a href="#cb385-11" aria-hidden="true" tabindex="-1"></a> x <span class="op"><</span> y <span class="ot">=</span> <span class="fu">compare</span> x y <span class="op">==</span> <span class="dt">LT</span></span>
|
||
<span id="cb385-12"><a href="#cb385-12" aria-hidden="true" tabindex="-1"></a> x <span class="op">>=</span> y <span class="ot">=</span> <span class="fu">compare</span> x y <span class="op">/=</span> <span class="dt">LT</span></span>
|
||
<span id="cb385-13"><a href="#cb385-13" aria-hidden="true" tabindex="-1"></a> x <span class="op">></span> y <span class="ot">=</span> <span class="fu">compare</span> x y <span class="op">==</span> <span class="dt">GT</span></span>
|
||
<span id="cb385-14"><a href="#cb385-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb385-15"><a href="#cb385-15" aria-hidden="true" tabindex="-1"></a> <span class="fu">max</span> x y <span class="op">|</span> x <span class="op"><=</span> y <span class="ot">=</span> y</span>
|
||
<span id="cb385-16"><a href="#cb385-16" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> x</span>
|
||
<span id="cb385-17"><a href="#cb385-17" aria-hidden="true" tabindex="-1"></a> <span class="fu">min</span> x y <span class="op">|</span> x <span class="op"><=</span> y <span class="ot">=</span> x</span>
|
||
<span id="cb385-18"><a href="#cb385-18" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> y</span></code></pre></div>
|
||
<p>With this definition it’s really hard to know what the minimal
|
||
complete definition is. Luckily the <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Prelude.html#t:Ord">docs
|
||
tell us</a> “Minimal complete definition: either compare or <=.”</p>
|
||
<p>As a final word on default implementations, if there is never a need
|
||
to override the default definition, the function can be moved out of the
|
||
class for simplicity. Consider a class like <code>Combine</code>
|
||
below:</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">class</span> <span class="dt">Combine</span> a <span class="kw">where</span></span>
|
||
<span id="cb386-2"><a href="#cb386-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> combine ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb386-3"><a href="#cb386-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> combine3 ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb386-4"><a href="#cb386-4" aria-hidden="true" tabindex="-1"></a> combine3 x y z <span class="ot">=</span> combine x (combine y z)</span></code></pre></div>
|
||
<p>It’s hard to think of a case where <code>combine3</code> would be
|
||
given any other definition, so why not move it out of the class:</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">class</span> <span class="dt">Combine</span> a <span class="kw">where</span></span>
|
||
<span id="cb387-2"><a href="#cb387-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> combine ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb387-3"><a href="#cb387-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb387-4"><a href="#cb387-4" aria-hidden="true" tabindex="-1"></a><span class="ot">combine3 ::</span> <span class="dt">Combine</span> a <span class="ot">=></span> a <span class="ot">-></span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb387-5"><a href="#cb387-5" aria-hidden="true" tabindex="-1"></a>combine3 x y z <span class="ot">=</span> combine x (combine y z)</span></code></pre></div>
|
||
<p>As an example, here are the <code>Eq</code> and <code>Ord</code>
|
||
instances for a simple pair type. Note how the definition uses the
|
||
minimal complete definition rules by only defining <code>==</code> and
|
||
<code><=</code>.</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">IntPair</span> <span class="ot">=</span> <span class="dt">IntPair</span> <span class="dt">Int</span> <span class="dt">Int</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="kw">instance</span> <span class="dt">Eq</span> <span class="dt">IntPair</span> <span class="kw">where</span></span>
|
||
<span id="cb388-5"><a href="#cb388-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">IntPair</span> a1 a2 <span class="op">==</span> <span class="dt">IntPair</span> b1 b2 <span class="ot">=</span> a1<span class="op">==</span>b1 <span class="op">&&</span> a2<span class="op">==</span>b2</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="kw">instance</span> <span class="dt">Ord</span> <span class="dt">IntPair</span> <span class="kw">where</span></span>
|
||
<span id="cb388-8"><a href="#cb388-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">IntPair</span> a1 a2 <span class="op"><=</span> <span class="dt">IntPair</span> b1 b2</span>
|
||
<span id="cb388-9"><a href="#cb388-9" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> a1<span class="op"><</span>b1 <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb388-10"><a href="#cb388-10" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> a1<span class="op">></span>b1 <span class="ot">=</span> <span class="dt">False</span></span>
|
||
<span id="cb388-11"><a href="#cb388-11" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> a2<span class="op"><=</span>b2</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><span class="op">*</span><span class="dt">Main</span><span class="op">></span> (<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">2</span>) <span class="op"><</span> (<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">3</span>)</span>
|
||
<span id="cb389-2"><a href="#cb389-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb389-3"><a href="#cb389-3" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> (<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">2</span>) <span class="op">></span> (<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">3</span>)</span>
|
||
<span id="cb389-4"><a href="#cb389-4" aria-hidden="true" tabindex="-1"></a><span class="dt">False</span></span>
|
||
<span id="cb389-5"><a href="#cb389-5" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span><span class="op">></span> <span class="fu">compare</span> (<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">2</span>) (<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">3</span>)</span>
|
||
<span id="cb389-6"><a href="#cb389-6" aria-hidden="true" tabindex="-1"></a><span class="dt">LT</span></span>
|
||
<span id="cb389-7"><a href="#cb389-7" aria-hidden="true" tabindex="-1"></a><span class="op">*</span><span class="dt">Main</span> <span class="dt">Data.List</span><span class="op">></span> <span class="fu">sort</span> [<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">1</span>,<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">4</span>,<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">1</span>,<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">2</span>]</span>
|
||
<span id="cb389-8"><a href="#cb389-8" aria-hidden="true" tabindex="-1"></a>[<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">1</span>,<span class="dt">IntPair</span> <span class="dv">1</span> <span class="dv">4</span>,<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">1</span>,<span class="dt">IntPair</span> <span class="dv">2</span> <span class="dv">2</span>]</span></code></pre></div>
|
||
<h2 data-number="6.3" id="useful-stuff"><span
|
||
class="header-section-number">6.3</span> Useful Stuff</h2>
|
||
<h3 data-number="6.3.1" id="deriving"><span
|
||
class="header-section-number">6.3.1</span> Deriving</h3>
|
||
<p>As we’ve seen many times already, <code>deriving</code> is a way to
|
||
get automatically generated class instances. The <code>Read</code> and
|
||
<code>Show</code> classes should pretty much always be derived to get
|
||
the standard behaviour. The derived instance for <code>Eq</code> is
|
||
typically what you want. It requires constructors and fields to
|
||
match.</p>
|
||
<p>The derived <code>Ord</code> instance might not be what you want. It
|
||
orders constructors left-to-right, and then compares fields inside
|
||
constructors left-to-right. An example:</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="kw">data</span> <span class="dt">Person</span> <span class="ot">=</span> <span class="dt">Dead</span> <span class="op">|</span> <span class="dt">Alive</span> <span class="dt">String</span> <span class="dt">Int</span></span>
|
||
<span id="cb390-2"><a href="#cb390-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>, <span class="dt">Eq</span>, <span class="dt">Ord</span>)</span></code></pre></div>
|
||
<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><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Dead</span> <span class="op"><</span> <span class="dt">Alive</span> <span class="st">"Bob"</span> <span class="dv">35</span> <span class="co">-- constructors are ordered left-to-right</span></span>
|
||
<span id="cb391-2"><a href="#cb391-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb391-3"><a href="#cb391-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Alive</span> <span class="st">"Barbara"</span> <span class="dv">35</span> <span class="op"><</span> <span class="dt">Alive</span> <span class="st">"Clive"</span> <span class="dv">17</span> <span class="co">-- names are compared before ages</span></span>
|
||
<span id="cb391-4"><a href="#cb391-4" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb391-5"><a href="#cb391-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">Alive</span> <span class="st">"Clive"</span> <span class="dv">17</span> <span class="op"><</span> <span class="dt">Alive</span> <span class="st">"Clive"</span> <span class="dv">30</span> <span class="co">-- finally, ages are compared if names match</span></span>
|
||
<span id="cb391-6"><a href="#cb391-6" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span></code></pre></div>
|
||
<h3 data-number="6.3.2" id="asking-ghci-about-classes"><span
|
||
class="header-section-number">6.3.2</span> Asking GHCi About
|
||
Classes</h3>
|
||
<p>You can use the <code>:info</code> command in GHCi to get the
|
||
contents and instances of a class. These days the info even includes the
|
||
minimal complete definition (see the MINIMAL pragma). For example:</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>info <span class="dt">Num</span></span>
|
||
<span id="cb392-2"><a href="#cb392-2" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Num</span> a <span class="kw">where</span></span>
|
||
<span id="cb392-3"><a href="#cb392-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> (+) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-4"><a href="#cb392-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> (-) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-5"><a href="#cb392-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> (*) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-6"><a href="#cb392-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> negate ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-7"><a href="#cb392-7" aria-hidden="true" tabindex="-1"></a><span class="ot"> abs ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-8"><a href="#cb392-8" aria-hidden="true" tabindex="-1"></a><span class="ot"> signum ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb392-9"><a href="#cb392-9" aria-hidden="true" tabindex="-1"></a><span class="ot"> fromInteger ::</span> <span class="dt">Integer</span> <span class="ot">-></span> a</span>
|
||
<span id="cb392-10"><a href="#cb392-10" aria-hidden="true" tabindex="-1"></a> <span class="ot">{-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}</span></span>
|
||
<span id="cb392-11"><a href="#cb392-11" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Defined in ‘GHC.Num’</span></span>
|
||
<span id="cb392-12"><a href="#cb392-12" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Word</span> <span class="co">-- Defined in ‘GHC.Num’</span></span>
|
||
<span id="cb392-13"><a href="#cb392-13" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Integer</span> <span class="co">-- Defined in ‘GHC.Num’</span></span>
|
||
<span id="cb392-14"><a href="#cb392-14" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Int</span> <span class="co">-- Defined in ‘GHC.Num’</span></span>
|
||
<span id="cb392-15"><a href="#cb392-15" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Float</span> <span class="co">-- Defined in ‘GHC.Float’</span></span>
|
||
<span id="cb392-16"><a href="#cb392-16" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> <span class="dt">Double</span> <span class="co">-- Defined in ‘GHC.Float’</span></span></code></pre></div>
|
||
<h2 data-number="6.4" id="hierarchies"><span
|
||
class="header-section-number">6.4</span> Hierarchies</h2>
|
||
<p>Both classes and instances can form <em>hierarchies</em>. This means
|
||
that a class or instance depends on another class or instance.</p>
|
||
<h3 data-number="6.4.1" id="instance-hierarchies"><span
|
||
class="header-section-number">6.4.1</span> Instance Hierarchies</h3>
|
||
<p>Let’s try to define an <code>Eq</code> instance for a simple pair
|
||
type:</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><span class="kw">data</span> <span class="dt">Pair</span> a <span class="ot">=</span> <span class="dt">MakePair</span> a a</span>
|
||
<span id="cb393-2"><a href="#cb393-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb393-3"><a href="#cb393-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb393-4"><a href="#cb393-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Eq</span> (<span class="dt">Pair</span> a) <span class="kw">where</span></span>
|
||
<span id="cb393-5"><a href="#cb393-5" aria-hidden="true" tabindex="-1"></a> (<span class="dt">MakePair</span> x y) <span class="op">==</span> (<span class="dt">MakePair</span> a b) <span class="ot">=</span> x<span class="op">==</span>a <span class="op">&&</span> y<span class="op">==</span>b</span></code></pre></div>
|
||
<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="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb394-2"><a href="#cb394-2" aria-hidden="true" tabindex="-1"></a> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Eq</span> a) arising from a use <span class="kw">of</span> ‘<span class="op">==</span>’</span>
|
||
<span id="cb394-3"><a href="#cb394-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Possible</span> fix<span class="op">:</span> add (<span class="dt">Eq</span> a) to the context <span class="kw">of</span> the <span class="kw">instance</span> declaration</span>
|
||
<span id="cb394-4"><a href="#cb394-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the first argument <span class="kw">of</span> ‘(<span class="op">&&</span>)’, namely ‘x <span class="op">==</span> a’</span>
|
||
<span id="cb394-5"><a href="#cb394-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> the expression<span class="op">:</span> x <span class="op">==</span> a <span class="op">&&</span> y <span class="op">==</span> b</span>
|
||
<span id="cb394-6"><a href="#cb394-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘<span class="op">==</span>’<span class="op">:</span></span>
|
||
<span id="cb394-7"><a href="#cb394-7" aria-hidden="true" tabindex="-1"></a> (<span class="dt">MakePair</span> x y) <span class="op">==</span> (<span class="dt">MakePair</span> a b) <span class="ot">=</span> x <span class="op">==</span> a <span class="op">&&</span> y <span class="op">==</span> b</span></code></pre></div>
|
||
<p>The compiler is trying to tell us that our <code>Eq (Pair a)</code>
|
||
instance needs an <code>Eq a</code> instance to work. How can we compare
|
||
pairs of values of type <code>a</code> if we can’t compare values of
|
||
type <code>a</code>? To solve this we need to add a type constraint to
|
||
the instance declaration, just like we’ve added type constraints to
|
||
function definitions.</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="kw">instance</span> <span class="dt">Eq</span> a <span class="ot">=></span> <span class="dt">Eq</span> (<span class="dt">Pair</span> a) <span class="kw">where</span></span>
|
||
<span id="cb395-2"><a href="#cb395-2" aria-hidden="true" tabindex="-1"></a> (<span class="dt">MakePair</span> x y) <span class="op">==</span> (<span class="dt">MakePair</span> a b) <span class="ot">=</span> x<span class="op">==</span>a <span class="op">&&</span> y<span class="op">==</span>b</span></code></pre></div>
|
||
<p>Now we can compare pairs, as long as the element type is comparable.
|
||
However, we can’t compare, say, pairs of functions, since functions
|
||
don’t have an Eq instance.</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="dt">Prelude</span><span class="op">></span> <span class="dt">MakePair</span> <span class="dv">1</span> <span class="dv">1</span> <span class="op">==</span> <span class="dt">MakePair</span> <span class="dv">1</span> <span class="dv">1</span></span>
|
||
<span id="cb396-2"><a href="#cb396-2" aria-hidden="true" tabindex="-1"></a><span class="dt">True</span></span>
|
||
<span id="cb396-3"><a href="#cb396-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span> <span class="op">==</span> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span></span>
|
||
<span id="cb396-4"><a href="#cb396-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb396-5"><a href="#cb396-5" aria-hidden="true" tabindex="-1"></a><span class="op"><</span>interactive<span class="op">>:</span><span class="dv">15</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="cb396-6"><a href="#cb396-6" aria-hidden="true" tabindex="-1"></a> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Eq</span> ([a0] <span class="ot">-></span> [a0])) arising from a use <span class="kw">of</span> ‘<span class="op">==</span>’</span>
|
||
<span id="cb396-7"><a href="#cb396-7" aria-hidden="true" tabindex="-1"></a> (<span class="fu">maybe</span> you haven't applied a function to enough arguments<span class="op">?</span>)</span>
|
||
<span id="cb396-8"><a href="#cb396-8" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the expression<span class="op">:</span></span>
|
||
<span id="cb396-9"><a href="#cb396-9" aria-hidden="true" tabindex="-1"></a> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span> <span class="op">==</span> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span></span>
|
||
<span id="cb396-10"><a href="#cb396-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span></span>
|
||
<span id="cb396-11"><a href="#cb396-11" aria-hidden="true" tabindex="-1"></a> it <span class="ot">=</span> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span> <span class="op">==</span> <span class="dt">MakePair</span> <span class="fu">reverse</span> <span class="fu">reverse</span></span></code></pre></div>
|
||
<p>Let’s continue with another example. Here’s a simple type class and
|
||
an instance</p>
|
||
<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="kw">class</span> <span class="dt">Check</span> a <span class="kw">where</span></span>
|
||
<span id="cb397-2"><a href="#cb397-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> check ::</span> a <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb397-3"><a href="#cb397-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb397-4"><a href="#cb397-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Check</span> <span class="dt">Int</span> <span class="kw">where</span></span>
|
||
<span id="cb397-5"><a href="#cb397-5" aria-hidden="true" tabindex="-1"></a> check x <span class="ot">=</span> x <span class="op">></span> <span class="dv">0</span></span></code></pre></div>
|
||
<p>Now we can write a function that checks a list. We use the standard
|
||
library function <code>and :: [Bool] -> Bool</code> that checks if a
|
||
list is all <code>True</code>s.</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="ot">checkAll ::</span> <span class="dt">Check</span> a <span class="ot">=></span> [a] <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb398-2"><a href="#cb398-2" aria-hidden="true" tabindex="-1"></a>checkAll xs <span class="ot">=</span> <span class="fu">and</span> (<span class="fu">map</span> check xs)</span></code></pre></div>
|
||
<p>In order to turn this into a <code>Check [a]</code> instance, we need
|
||
to add a constraint to the instance declaration. Our
|
||
<code>Check [a]</code> is based on the <code>Check a</code>
|
||
instance.</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="kw">instance</span> <span class="dt">Check</span> a <span class="ot">=></span> <span class="dt">Check</span> [a] <span class="kw">where</span></span>
|
||
<span id="cb399-2"><a href="#cb399-2" aria-hidden="true" tabindex="-1"></a> check xs <span class="ot">=</span> <span class="fu">and</span> (<span class="fu">map</span> check xs)</span></code></pre></div>
|
||
<p>This means that our <code>Check [a]</code> instance is only valid
|
||
when there is a corresponding <code>Check a</code> instance. For
|
||
example, if we try to invoke a <code>Check [Bool]</code> instance, we
|
||
get an error about the missing <code>Check Bool</code> instance:</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="dt">Prelude</span><span class="op">></span> check [<span class="dt">True</span>,<span class="dt">False</span>]</span>
|
||
<span id="cb400-2"><a href="#cb400-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb400-3"><a href="#cb400-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">1</span><span class="op">:</span> <span class="fu">error</span><span class="op">:</span></span>
|
||
<span id="cb400-4"><a href="#cb400-4" aria-hidden="true" tabindex="-1"></a> • <span class="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Check</span> <span class="dt">Bool</span>) arising from a use <span class="kw">of</span> ‘check’</span>
|
||
<span id="cb400-5"><a href="#cb400-5" aria-hidden="true" tabindex="-1"></a> • <span class="dt">In</span> the expression<span class="op">:</span> check [<span class="dt">True</span>, <span class="dt">False</span>]</span>
|
||
<span id="cb400-6"><a href="#cb400-6" aria-hidden="true" tabindex="-1"></a> <span class="dt">In</span> an equation for ‘it’<span class="op">:</span> it <span class="ot">=</span> check [<span class="dt">True</span>, <span class="dt">False</span>]</span></code></pre></div>
|
||
<p>Also, if we try to define <code>Check [a]</code> instance without the
|
||
constraint, we get an error (with a pretty good suggestion!)</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="dt">No</span> <span class="kw">instance</span> for (<span class="dt">Check</span> a) arising from a use <span class="kw">of</span> ‘check’</span>
|
||
<span id="cb401-2"><a href="#cb401-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">Possible</span> fix<span class="op">:</span></span>
|
||
<span id="cb401-3"><a href="#cb401-3" aria-hidden="true" tabindex="-1"></a> add (<span class="dt">Check</span> a) to the context <span class="kw">of</span> the <span class="kw">instance</span> declaration</span></code></pre></div>
|
||
<p>Finally, sometimes multiple constraints are needed. Consider for
|
||
example the <code>Eq</code> instance for <code>Either</code>:</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="kw">instance</span> (<span class="dt">Eq</span> a, <span class="dt">Eq</span> b) <span class="ot">=></span> <span class="dt">Eq</span> (<span class="dt">Either</span> a b) <span class="kw">where</span></span>
|
||
<span id="cb402-2"><a href="#cb402-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">Left</span> x <span class="op">==</span> <span class="dt">Left</span> y <span class="ot">=</span> x<span class="op">==</span>y</span>
|
||
<span id="cb402-3"><a href="#cb402-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Right</span> x <span class="op">==</span> <span class="dt">Right</span> y <span class="ot">=</span> x<span class="op">==</span>y</span>
|
||
<span id="cb402-4"><a href="#cb402-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="6.4.2" id="class-hierarchy"><span
|
||
class="header-section-number">6.4.2</span> Class Hierarchy</h3>
|
||
<p>Respectively, a class can depend on another class. This is useful for
|
||
instance when you want to use functions from another class in your
|
||
default implementations:</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="kw">class</span> <span class="dt">Size</span> a <span class="kw">where</span></span>
|
||
<span id="cb403-2"><a href="#cb403-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> size ::</span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb403-3"><a href="#cb403-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb403-4"><a href="#cb403-4" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Size</span> a <span class="ot">=></span> <span class="dt">SizeBoth</span> a <span class="kw">where</span></span>
|
||
<span id="cb403-5"><a href="#cb403-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> sizeBoth ::</span> a <span class="ot">-></span> a <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb403-6"><a href="#cb403-6" aria-hidden="true" tabindex="-1"></a> sizeBoth x y <span class="ot">=</span> size x <span class="op">+</span> size y</span></code></pre></div>
|
||
<p>In cases like this we say <code>SizeBoth</code> is a
|
||
<em>subclass</em> of <code>Size</code>. Note again the confusion with
|
||
object oriented programming. Examples of subclasses in the standard
|
||
library include:</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="kw">class</span> <span class="dt">Eq</span> a <span class="ot">=></span> <span class="dt">Ord</span> a <span class="kw">where</span></span>
|
||
<span id="cb404-2"><a href="#cb404-2" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span>
|
||
<span id="cb404-3"><a href="#cb404-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Fractional</span> a <span class="kw">where</span></span>
|
||
<span id="cb404-4"><a href="#cb404-4" aria-hidden="true" tabindex="-1"></a> <span class="op">...</span></span></code></pre></div>
|
||
<p>Another way to look at subclasses is that if you have a
|
||
<code>class Main a => Sub a</code>, you must provide an
|
||
<code>instance Main MyType</code> in order to be able to declare
|
||
<code>instance Sub MyType</code>.</p>
|
||
<h2 data-number="6.5" id="quiz-5"><span
|
||
class="header-section-number">6.5</span> Quiz</h2>
|
||
<p>What are the functions in the <code>Eq</code> class?</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
<code>(==), (/=)</code>
|
||
</li>
|
||
<li>
|
||
<code>(==)</code>
|
||
</li>
|
||
<li>
|
||
<code>(==)</code>, <code>(<)</code>, <code>(>)</code>
|
||
</li>
|
||
</ol>
|
||
<p>For which of the following classes can we get automatic instances
|
||
with <code>deriving</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>Num</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Ord</code>
|
||
</li>
|
||
<li>
|
||
<code>Size</code>
|
||
</li>
|
||
</ol>
|
||
<p>Given the following definition of the class
|
||
<code>BitOperations</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="kw">class</span> <span class="dt">BitOperations</span> a <span class="kw">where</span></span>
|
||
<span id="cb405-2"><a href="#cb405-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> bitNot ::</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb405-3"><a href="#cb405-3" aria-hidden="true" tabindex="-1"></a> bitNot x <span class="ot">=</span> bitNand x x</span>
|
||
<span id="cb405-4"><a href="#cb405-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> bitAnd ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb405-5"><a href="#cb405-5" aria-hidden="true" tabindex="-1"></a> bitAnd x y <span class="ot">=</span> bitNot (bitOr (bitNot x) (bitNot y))</span>
|
||
<span id="cb405-6"><a href="#cb405-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> bitOr ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb405-7"><a href="#cb405-7" aria-hidden="true" tabindex="-1"></a> bitOr x y <span class="ot">=</span> bitNot (bitAnd (bitNot x) (bitNot y))</span>
|
||
<span id="cb405-8"><a href="#cb405-8" aria-hidden="true" tabindex="-1"></a><span class="ot"> bitNand ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb405-9"><a href="#cb405-9" aria-hidden="true" tabindex="-1"></a> bitNand x y <span class="ot">=</span> bitNot (bitAnd x y)</span></code></pre></div>
|
||
<p>which set of operations is <em>not</em> a minimal complete definition
|
||
of <code>BitOperations</code>?</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
<code>bitNand, bitAnd</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>bitAnd, bitOr</code>
|
||
</li>
|
||
<li>
|
||
<code>bitAnd, bitNot</code>
|
||
</li>
|
||
<li>
|
||
<code>bitNot, bitOr</code>
|
||
</li>
|
||
</ol>
|
||
<p>The declaration <code>instance Num a => Eq (Pair a)</code> tells
|
||
me that</p>
|
||
<ol class="quiz">
|
||
<li>
|
||
All instances of <code>Num</code> are instances of <code>Eq</code>
|
||
</li>
|
||
<li class="correct">
|
||
<code>Pair a</code> is an instance of <code>Eq</code> if <code>a</code>
|
||
is an instance of <code>Num</code>
|
||
</li>
|
||
<li>
|
||
The instance <code>Eq (Pair a)</code> inherits the instance
|
||
<code>Num a</code>
|
||
</li>
|
||
</ol>
|
||
<p>The declaration <code>class Num a => Fractional a</code> tells me
|
||
that</p>
|
||
<ol class="quiz">
|
||
<li class="correct">
|
||
All instances of <code>Fractional</code> must be instances of
|
||
<code>Num</code>
|
||
</li>
|
||
<li>
|
||
All instances of <code>Num</code> must be instances of
|
||
<code>Fractional</code>
|
||
</li>
|
||
<li>
|
||
If I define an instance for <code>Fractional</code>, I also get an
|
||
instance for <code>Num</code>
|
||
</li>
|
||
<li>
|
||
If I define an instance for <code>Num</code>, I also get an instance for
|
||
<code>Fractional</code>
|
||
</li>
|
||
</ol>
|
||
<h2 data-number="6.6" id="exercises-5"><span
|
||
class="header-section-number">6.6</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set6.hs">Set6</a>:
|
||
defining classes and instances</li>
|
||
</ul>
|
||
<h1 data-number="7" id="lecture-7-new-constellations"><span
|
||
class="header-section-number">7</span> Lecture 7: New
|
||
Constellations</h1>
|
||
<p>This lecture offers an introduction to <em>design patterns</em> for
|
||
<em>typed functional programming</em>. These patterns are both useful
|
||
when writing Haskell programs, and offer a nice arena for practicing
|
||
skills from the previous lectures.</p>
|
||
<h2 data-number="7.1" id="modeling-with-boxes"><span
|
||
class="header-section-number">7.1</span> Modeling with Boxes</h2>
|
||
<p>Sometimes you don’t need a new type, but instead can just reuse a
|
||
standard type. For example, repesenting car register plate numbers with
|
||
<code>String</code>. However, if your code is full of
|
||
<code>String</code>s, it can be easy to accidentally mix up e.g. a car’s
|
||
model and registration in a function like
|
||
<code>registerCar :: String -> String -> CarRegistry -> CarRegistry</code>.</p>
|
||
<p>For situations like this it’s common to create a new type that just
|
||
contains a <code>String</code> (a “boxed” string):</p>
|
||
<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="kw">data</span> <span class="dt">Plate</span> <span class="ot">=</span> <span class="dt">Plate</span> <span class="dt">String</span></span>
|
||
<span id="cb406-2"><a href="#cb406-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>We can now give <code>registerCar</code> a slightly nicer type,
|
||
<code>String -> Plate -> CarRegistry -> CarRegistry</code>.
|
||
Additionally, we can restrict the operations that are possible on
|
||
<code>Plate</code>s to a subset of those that are possible on strings.
|
||
For example, there is no need to combine the register plate numbers of
|
||
two cars. Thus we don’t need to offer a function
|
||
<code>concatPlates :: Plate -> Plate -> Plate</code>. We can also
|
||
define a <em>smart constructor</em> for <code>Plate</code> that checks
|
||
that the register number is in the correct format:</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="ot">parsePlate ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Maybe</span> <span class="dt">Plate</span></span>
|
||
<span id="cb407-2"><a href="#cb407-2" aria-hidden="true" tabindex="-1"></a>parsePlate string</span>
|
||
<span id="cb407-3"><a href="#cb407-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> correctPlateNumber string <span class="ot">=</span> <span class="dt">Just</span> (<span class="dt">Plate</span> string)</span>
|
||
<span id="cb407-4"><a href="#cb407-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>Here’s another example: representing money. If we just store money as
|
||
<code>Int</code>s, the compiler won’t protect us from mistakes like
|
||
multiplying money with money. If instead we implement our own
|
||
<code>Money</code> type that wraps <code>Int</code>, we get type safety.
|
||
Additionally, we can encapsulate the fact that money is represented as
|
||
an integer amount of cents.</p>
|
||
<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="kw">data</span> <span class="dt">Money</span> <span class="ot">=</span> <span class="dt">Money</span> <span class="dt">Int</span></span>
|
||
<span id="cb408-2"><a href="#cb408-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb408-3"><a href="#cb408-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb408-4"><a href="#cb408-4" aria-hidden="true" tabindex="-1"></a><span class="ot">renderMoney ::</span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb408-5"><a href="#cb408-5" aria-hidden="true" tabindex="-1"></a>renderMoney (<span class="dt">Money</span> cents) <span class="ot">=</span> <span class="fu">show</span> (<span class="fu">fromIntegral</span> cents <span class="op">/</span> <span class="dv">100</span>)</span>
|
||
<span id="cb408-6"><a href="#cb408-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb408-7"><a href="#cb408-7" aria-hidden="true" tabindex="-1"></a><span class="ot">(+!) ::</span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Money</span></span>
|
||
<span id="cb408-8"><a href="#cb408-8" aria-hidden="true" tabindex="-1"></a>(<span class="dt">Money</span> a) <span class="op">+!</span> (<span class="dt">Money</span> b) <span class="ot">=</span> <span class="dt">Money</span> (a<span class="op">+</span>b)</span>
|
||
<span id="cb408-9"><a href="#cb408-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb408-10"><a href="#cb408-10" aria-hidden="true" tabindex="-1"></a><span class="ot">scale ::</span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Money</span></span>
|
||
<span id="cb408-11"><a href="#cb408-11" aria-hidden="true" tabindex="-1"></a>scale (<span class="dt">Money</span> a) x <span class="ot">=</span> <span class="dt">Money</span> (<span class="fu">round</span> (<span class="fu">fromIntegral</span> a <span class="op">*</span> x))</span>
|
||
<span id="cb408-12"><a href="#cb408-12" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb408-13"><a href="#cb408-13" aria-hidden="true" tabindex="-1"></a><span class="ot">addVat ::</span> <span class="dt">Money</span> <span class="ot">-></span> <span class="dt">Money</span></span>
|
||
<span id="cb408-14"><a href="#cb408-14" aria-hidden="true" tabindex="-1"></a>addVat m <span class="ot">=</span> m <span class="op">+!</span> scale m <span class="fl">0.24</span></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>renderMoney (<span class="dt">Money</span> <span class="dv">100</span> <span class="op">+!</span> <span class="dt">Money</span> <span class="dv">150</span>)</span>
|
||
<span id="cb409-2"><a href="#cb409-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="st">"2.5"</span></span>
|
||
<span id="cb409-3"><a href="#cb409-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb409-4"><a href="#cb409-4" aria-hidden="true" tabindex="-1"></a>scale (<span class="dt">Money</span> <span class="dv">299</span>) <span class="fl">0.24</span></span>
|
||
<span id="cb409-5"><a href="#cb409-5" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Money</span> <span class="dv">72</span></span>
|
||
<span id="cb409-6"><a href="#cb409-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb409-7"><a href="#cb409-7" aria-hidden="true" tabindex="-1"></a>addVat (<span class="dt">Money</span> <span class="dv">299</span>)</span>
|
||
<span id="cb409-8"><a href="#cb409-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dt">Money</span> <span class="dv">371</span></span></code></pre></div>
|
||
<p><strong>Note!</strong> If you’re familiar with Object-Oriented
|
||
Programming, this is a bit like encapsulation.</p>
|
||
<h2 data-number="7.2" id="modeling-with-cases"><span
|
||
class="header-section-number">7.2</span> Modeling with Cases</h2>
|
||
<p>Haskell’s algebraic datatypes are really powerful at modeling things
|
||
based on <em>cases</em>. It’s often useful to think of types as defining
|
||
the set of possible cases, and functions <em>handling</em> those cases
|
||
(often via pattern matching). Let’s look at two examples.</p>
|
||
<p>Since it’s so easy to define custom types in Haskell, it’s quite
|
||
convenient to use more descriptive types instead of booleans or strings.
|
||
Consider a list of persons. In some other language if you wanted to sort
|
||
the persons into ascending order by name you might use a call like
|
||
<code>sortPersons(persons, "name", true)</code>. In Haskell you can do
|
||
this instead:</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="kw">data</span> <span class="dt">Person</span> <span class="ot">=</span> <span class="dt">Person</span> {<span class="ot">name ::</span> <span class="dt">String</span>,<span class="ot"> age ::</span> <span class="dt">Int</span>}</span>
|
||
<span id="cb410-2"><a href="#cb410-2" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> <span class="dt">Show</span></span>
|
||
<span id="cb410-3"><a href="#cb410-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb410-4"><a href="#cb410-4" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">SortOrder</span> <span class="ot">=</span> <span class="dt">Ascending</span> <span class="op">|</span> <span class="dt">Descending</span></span>
|
||
<span id="cb410-5"><a href="#cb410-5" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">SortField</span> <span class="ot">=</span> <span class="dt">Name</span> <span class="op">|</span> <span class="dt">Age</span></span>
|
||
<span id="cb410-6"><a href="#cb410-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb410-7"><a href="#cb410-7" aria-hidden="true" tabindex="-1"></a><span class="ot">sortByField ::</span> <span class="dt">SortField</span> <span class="ot">-></span> [<span class="dt">Person</span>] <span class="ot">-></span> [<span class="dt">Person</span>]</span>
|
||
<span id="cb410-8"><a href="#cb410-8" aria-hidden="true" tabindex="-1"></a>sortByField <span class="dt">Name</span> ps <span class="ot">=</span> sortBy (comparing name) ps</span>
|
||
<span id="cb410-9"><a href="#cb410-9" aria-hidden="true" tabindex="-1"></a>sortByField <span class="dt">Age</span> ps <span class="ot">=</span> sortBy (comparing age) ps</span>
|
||
<span id="cb410-10"><a href="#cb410-10" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb410-11"><a href="#cb410-11" aria-hidden="true" tabindex="-1"></a><span class="ot">sortPersons ::</span> <span class="dt">SortField</span> <span class="ot">-></span> <span class="dt">SortOrder</span> <span class="ot">-></span> [<span class="dt">Person</span>] <span class="ot">-></span> [<span class="dt">Person</span>]</span>
|
||
<span id="cb410-12"><a href="#cb410-12" aria-hidden="true" tabindex="-1"></a>sortPersons field <span class="dt">Ascending</span> ps <span class="ot">=</span> sortByField field ps</span>
|
||
<span id="cb410-13"><a href="#cb410-13" aria-hidden="true" tabindex="-1"></a>sortPersons field <span class="dt">Descending</span> ps <span class="ot">=</span> <span class="fu">reverse</span> (sortByField field ps)</span>
|
||
<span id="cb410-14"><a href="#cb410-14" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb410-15"><a href="#cb410-15" aria-hidden="true" tabindex="-1"></a>persons <span class="ot">=</span> [<span class="dt">Person</span> <span class="st">"Fridolf"</span> <span class="dv">73</span>, <span class="dt">Person</span> <span class="st">"Greta"</span> <span class="dv">60</span>, <span class="dt">Person</span> <span class="st">"Hans"</span> <span class="dv">65</span>]</span></code></pre></div>
|
||
<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>sortPersons <span class="dt">Name</span> <span class="dt">Ascending</span> persons</span>
|
||
<span id="cb411-2"><a href="#cb411-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Fridolf"</span>, age <span class="ot">=</span> <span class="dv">73</span>},<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Greta"</span>, age <span class="ot">=</span> <span class="dv">60</span>},<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Hans"</span>, age <span class="ot">=</span> <span class="dv">65</span>}]</span>
|
||
<span id="cb411-3"><a href="#cb411-3" aria-hidden="true" tabindex="-1"></a>sortPersons <span class="dt">Age</span> <span class="dt">Descending</span> persons</span>
|
||
<span id="cb411-4"><a href="#cb411-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> [<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Fridolf"</span>, age <span class="ot">=</span> <span class="dv">73</span>},<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Hans"</span>, age <span class="ot">=</span> <span class="dv">65</span>},<span class="dt">Person</span> {name <span class="ot">=</span> <span class="st">"Greta"</span>, age <span class="ot">=</span> <span class="dv">60</span>}]</span></code></pre></div>
|
||
<p>Note how you can’t accidentally typo the field name (unlike with
|
||
strings), and how you don’t need to remember whether <code>true</code>
|
||
refers to ascending or descending order.</p>
|
||
<p>Let’s move on to the next example. Many Haskell functions don’t work
|
||
with empty lists (consider <code>head []</code>). If you’re writing code
|
||
that needs to track whether lists are possibly empty or guaranteed to
|
||
not be empty, you can use the <code>NonEmpty</code> type from the <a
|
||
href="https://hackage.haskell.org/package/base-4.16.4.0/docs/Data-List-NonEmpty.html">Data.List.NonEmpty</a>
|
||
module.</p>
|
||
<p>Consider the definition of <code>NonEmpty</code>:</p>
|
||
<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><span class="kw">data</span> <span class="dt">NonEmpty</span> a <span class="ot">=</span> a <span class="op">:|</span> [a]</span></code></pre></div>
|
||
<p>Here the type represents a <em>lack of</em> cases. The type
|
||
<code>NonEmpty a</code> will always consist of a value of type
|
||
<code>a</code>, and some further <code>a</code>s, collected in a list.
|
||
Here are some example values of <code>NonEmpty Int</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="dv">1</span> <span class="op">:|</span> [<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span>
|
||
<span id="cb413-2"><a href="#cb413-2" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span> <span class="op">:|</span> []</span></code></pre></div>
|
||
<p>By the way, this is also an example of an <em>infix constructor</em>.
|
||
We’ve already met another infix constructor earlier, the list
|
||
constructor <code>(:)</code>. Any operator that begins with a colon (the
|
||
<code>:</code> character) can be used as an infix constructor. We can
|
||
pattern match on <code>(:|)</code> just like on <code>(:)</code>, as
|
||
you’ll see in the examples below.</p>
|
||
<p>Here are the functions that convert between normal lists and nonempty
|
||
lists. Note how we can’t have a function
|
||
<code>[a] -> NonEmpty a</code>, but must instead use
|
||
<code>Maybe</code> to represent the possibility that the list was,
|
||
indeed, empty. Note also how <code>toList</code> has only one equation,
|
||
we can’t have a <code>toList []</code> situation due to the type
|
||
<code>NonEmpty</code>.</p>
|
||
<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="ot">nonEmpty ::</span> [a] <span class="ot">-></span> <span class="dt">Maybe</span> (<span class="dt">NonEmpty</span> a)</span>
|
||
<span id="cb414-2"><a href="#cb414-2" aria-hidden="true" tabindex="-1"></a>nonEmpty [] <span class="ot">=</span> <span class="dt">Nothing</span></span>
|
||
<span id="cb414-3"><a href="#cb414-3" aria-hidden="true" tabindex="-1"></a>nonEmpty (x<span class="op">:</span>xs) <span class="ot">=</span> <span class="dt">Just</span> (x <span class="op">:|</span> xs)</span>
|
||
<span id="cb414-4"><a href="#cb414-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb414-5"><a href="#cb414-5" aria-hidden="true" tabindex="-1"></a><span class="ot">toList ::</span> <span class="dt">NonEmpty</span> a <span class="ot">-></span> [a]</span>
|
||
<span id="cb414-6"><a href="#cb414-6" aria-hidden="true" tabindex="-1"></a>toList (x <span class="op">:|</span> xs) <span class="ot">=</span> x <span class="op">:</span> xs</span></code></pre></div>
|
||
<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>nonEmpty [<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">1</span> <span class="op">:|</span> [<span class="dv">2</span>,<span class="dv">3</span>])</span>
|
||
<span id="cb415-2"><a href="#cb415-2" aria-hidden="true" tabindex="-1"></a>nonEmpty [<span class="dv">1</span>] <span class="op">==></span> <span class="dt">Just</span> (<span class="dv">1</span> <span class="op">:|</span> [])</span>
|
||
<span id="cb415-3"><a href="#cb415-3" aria-hidden="true" tabindex="-1"></a>nonEmpty [] <span class="op">==></span> <span class="dt">Nothing</span></span>
|
||
<span id="cb415-4"><a href="#cb415-4" aria-hidden="true" tabindex="-1"></a>toList (<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">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span></code></pre></div>
|
||
<p>Here are <code>head</code> and <code>last</code> implemented for
|
||
<code>NonEmpty</code>:</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>neHead (x <span class="op">:|</span> _) <span class="ot">=</span> x</span>
|
||
<span id="cb416-2"><a href="#cb416-2" aria-hidden="true" tabindex="-1"></a>neLast (x <span class="op">:|</span> []) <span class="ot">=</span> x</span>
|
||
<span id="cb416-3"><a href="#cb416-3" aria-hidden="true" tabindex="-1"></a>neLast (_ <span class="op">:|</span> xs) <span class="ot">=</span> <span class="fu">last</span> xs</span></code></pre></div>
|
||
<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>neHead (<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">1</span></span>
|
||
<span id="cb417-2"><a href="#cb417-2" aria-hidden="true" tabindex="-1"></a>neLast (<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">3</span></span></code></pre></div>
|
||
<p>By the way, these functions are available as
|
||
<code>Data.List.NonEmpty.head</code> and
|
||
<code>Data.List.NonEmpty.last</code> along with many other useful
|
||
functions.</p>
|
||
<p>In summary, if you write types that represent all possible cases for
|
||
your values, and then write functions that handle those cases, your code
|
||
will be simple and correct.</p>
|
||
<h2 data-number="7.3" id="monoids"><span
|
||
class="header-section-number">7.3</span> Monoids</h2>
|
||
<!-- TODO: Give an example of a semigroup that is not a monoid. -->
|
||
<!-- TODO: move to the end of the lecture? -->
|
||
<p>A pattern that comes up surprisingly often in functional programming
|
||
is the <em>monoid</em> (not to be confused with a <em>monad</em>!).
|
||
Explanations of monoids are often very mathematical, but the idea is
|
||
simple: combining things.</p>
|
||
<h3 data-number="7.3.1" id="associative-operations"><span
|
||
class="header-section-number">7.3.1</span> Associative Operations</h3>
|
||
<p>Many functions and operators we use are <em>associative</em>. This is
|
||
just a fancy way of saying they don’t need parentheses. For example, all
|
||
of these expressions have the value 16 because addition is
|
||
associative:</p>
|
||
<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="dv">1</span> <span class="op">+</span> <span class="dv">3</span>) <span class="op">+</span> (<span class="dv">5</span> <span class="op">+</span> <span class="dv">7</span>)</span>
|
||
<span id="cb418-2"><a href="#cb418-2" aria-hidden="true" tabindex="-1"></a> <span class="dv">1</span> <span class="op">+</span> (<span class="dv">3</span> <span class="op">+</span> (<span class="dv">5</span> <span class="op">+</span> <span class="dv">7</span>))</span>
|
||
<span id="cb418-3"><a href="#cb418-3" aria-hidden="true" tabindex="-1"></a> <span class="dv">1</span> <span class="op">+</span> <span class="dv">3</span> <span class="op">+</span> <span class="dv">5</span> <span class="op">+</span> <span class="dv">7</span></span></code></pre></div>
|
||
<p>Examples of associative operations are easy to come by in Haskell.
|
||
For example the <code>++</code> operator for catenating lists is
|
||
associative: it doesn’t matter whether you do
|
||
<code>([1] ++ [2,3]) ++ [4]</code> or <code>[1] ++ ([2,3] ++ [4])</code>
|
||
– the result is <code>[1,2,3,4]</code>.</p>
|
||
<p>Another great example is the function composition operator. Both
|
||
<code>(head . tail) . tail</code> and <code>head . (tail . tail)</code>
|
||
compute the third element of a list.</p>
|
||
<p>However not all operators are associative. The most familiar examples
|
||
are subtraction and exponentiation. <code>(1-2)-3</code> is
|
||
<code>-4</code> but <code>1-(2-3)</code> is <code>2</code>. Similarly,
|
||
<code>(2^3)^2</code> is <code>64</code> while <code>2^(3^2)</code> is
|
||
512. One needs to be careful with parentheses when using operators that
|
||
are not associative.</p>
|
||
<p>Another operator that’s not associative is the list constructor,
|
||
<code>(:)</code>. This time the reason is even more fundamental: while
|
||
<code>True:(False:[])</code> is ok, <code>(True:False):[]</code> does
|
||
not even type! In order for an operation to be associative, it needs to
|
||
take two arguments of the same type.</p>
|
||
<p>In addition to operators, functions can also be associative. The
|
||
syntax looks a bit different, but a function <code>f</code> is
|
||
associative if these are the same:</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>f x (f y z)</span>
|
||
<span id="cb419-2"><a href="#cb419-2" aria-hidden="true" tabindex="-1"></a>f (f x y) z</span></code></pre></div>
|
||
<p>Two widely-used associative functions are the <code>min</code> and
|
||
<code>max</code> functions:</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="fu">min</span> <span class="dv">2</span> (<span class="fu">min</span> <span class="dv">1</span> <span class="dv">3</span>) <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb420-2"><a href="#cb420-2" aria-hidden="true" tabindex="-1"></a><span class="fu">min</span> (<span class="fu">min</span> <span class="dv">2</span> <span class="dv">1</span>) <span class="dv">3</span> <span class="op">==></span> <span class="dv">1</span></span>
|
||
<span id="cb420-3"><a href="#cb420-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb420-4"><a href="#cb420-4" aria-hidden="true" tabindex="-1"></a><span class="fu">max</span> <span class="dv">2</span> (<span class="fu">max</span> <span class="dv">1</span> <span class="dv">3</span>) <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb420-5"><a href="#cb420-5" aria-hidden="true" tabindex="-1"></a><span class="fu">max</span> (<span class="fu">max</span> <span class="dv">2</span> <span class="dv">1</span>) <span class="dv">3</span> <span class="op">==></span> <span class="dv">3</span></span></code></pre></div>
|
||
<h3 data-number="7.3.2" id="semigroups"><span
|
||
class="header-section-number">7.3.2</span> Semigroups</h3>
|
||
<p>Mathematically speaking, an associative function (or operator) forms
|
||
a <em>semigroup</em>. Haskell has a type class <code>Semigroup</code>
|
||
(defined in the module <code>Data.Semigroup</code>) that can be used
|
||
when a type has one clear associative operation.</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="kw">class</span> <span class="dt">Semigroup</span> a <span class="kw">where</span></span>
|
||
<span id="cb421-2"><a href="#cb421-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- An associative operation.</span></span>
|
||
<span id="cb421-3"><a href="#cb421-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<>) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span></code></pre></div>
|
||
<p>Lists are an instance of <code>Semigroup</code> with
|
||
<code>(++)</code> as <code>(<>)</code>:</p>
|
||
<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="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="op">==></span> [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span></code></pre></div>
|
||
<p>Types that have multiple different associative operators usually
|
||
aren’t made an instance of Semigroup. An example is <code>Int</code>,
|
||
which has many associative functions like <code>+</code>, <code>*</code>
|
||
and <code>max</code>. Instead, the Haskell standard library uses boxing
|
||
(see earlier in this lecture). Here are the definitions for
|
||
<code>Sum</code> and <code>Product</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="kw">data</span> <span class="dt">Sum</span> a <span class="ot">=</span> <span class="dt">Sum</span> a</span>
|
||
<span id="cb423-2"><a href="#cb423-2" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Semigroup</span> (<span class="dt">Sum</span> a) <span class="kw">where</span></span>
|
||
<span id="cb423-3"><a href="#cb423-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">Sum</span> a <span class="op"><></span> <span class="dt">Sum</span> b <span class="ot">=</span> <span class="dt">Sum</span> (a<span class="op">+</span>b)</span>
|
||
<span id="cb423-4"><a href="#cb423-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb423-5"><a href="#cb423-5" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Product</span> a <span class="ot">=</span> <span class="dt">Product</span> a</span>
|
||
<span id="cb423-6"><a href="#cb423-6" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Semigroup</span> (<span class="dt">Product</span> a) <span class="kw">where</span></span>
|
||
<span id="cb423-7"><a href="#cb423-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">Product</span> a <span class="op"><></span> <span class="dt">Product</span> b <span class="ot">=</span> <span class="dt">Product</span> (a<span class="op">*</span>b)</span></code></pre></div>
|
||
<p>By the way, this is another benefit of boxing things: being able to
|
||
declare different type class instances!</p>
|
||
<p>Note how the <code>Num a</code> constraint lets us use
|
||
<code>Num</code> operations like <code>+</code> and <code>*</code> on
|
||
the contained type <code>a</code>. We can have values like
|
||
<code>Sum "abc" :: Sum String</code>, but they won’t have a
|
||
<code>Semigroup</code> instance!</p>
|
||
<p>Similarly, we have box types <code>Min</code> and <code>Max</code>.
|
||
Let’s play around in GHCi a bit:</p>
|
||
<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="dt">Prelude</span><span class="op">></span> <span class="kw">import</span> <span class="dt">Data.Semigroup</span></span>
|
||
<span id="cb424-2"><a href="#cb424-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Semigroup</span><span class="op">></span> <span class="dt">Product</span> (<span class="dv">2</span><span class="ot">::</span><span class="dt">Int</span>) <span class="op"><></span> <span class="dt">Product</span> <span class="dv">3</span> <span class="op"><></span> <span class="dt">Product</span> <span class="dv">1</span></span>
|
||
<span id="cb424-3"><a href="#cb424-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Product</span> {getProduct <span class="ot">=</span> <span class="dv">6</span>}</span>
|
||
<span id="cb424-4"><a href="#cb424-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Semigroup</span><span class="op">></span> <span class="dt">Sum</span> <span class="dv">3</span> <span class="op"><></span> <span class="dt">Sum</span> <span class="dv">5</span> <span class="op"><></span> <span class="dt">Sum</span> <span class="dv">7</span></span>
|
||
<span id="cb424-5"><a href="#cb424-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Sum</span> {getSum <span class="ot">=</span> <span class="dv">15</span>}</span>
|
||
<span id="cb424-6"><a href="#cb424-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Semigroup</span><span class="op">></span> <span class="dt">Product</span> <span class="dv">2</span> <span class="op"><></span> <span class="dt">Product</span> <span class="dv">3</span> <span class="op"><></span> <span class="dt">Product</span> <span class="dv">1</span></span>
|
||
<span id="cb424-7"><a href="#cb424-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Product</span> {getProduct <span class="ot">=</span> <span class="dv">6</span>}</span>
|
||
<span id="cb424-8"><a href="#cb424-8" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Semigroup</span><span class="op">></span> <span class="dt">Min</span> <span class="dv">4</span> <span class="op"><></span> <span class="dt">Min</span> <span class="dv">3</span> <span class="op"><></span> <span class="dt">Min</span> <span class="dv">5</span></span>
|
||
<span id="cb424-9"><a href="#cb424-9" aria-hidden="true" tabindex="-1"></a><span class="dt">Min</span> {getMin <span class="ot">=</span> <span class="dv">3</span>}</span>
|
||
<span id="cb424-10"><a href="#cb424-10" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span> <span class="dt">Data.Semigroup</span><span class="op">></span> <span class="dt">Max</span> <span class="dv">4</span> <span class="op"><></span> <span class="dt">Max</span> <span class="dv">3</span> <span class="op"><></span> <span class="dt">Max</span> <span class="dv">5</span></span>
|
||
<span id="cb424-11"><a href="#cb424-11" aria-hidden="true" tabindex="-1"></a><span class="dt">Max</span> {getMax <span class="ot">=</span> <span class="dv">5</span>}</span></code></pre></div>
|
||
<h3 data-number="7.3.3" id="finally-monoids"><span
|
||
class="header-section-number">7.3.3</span> Finally, Monoids</h3>
|
||
<p>If we listen to the mathematicians for a moment again, a
|
||
<em>monoid</em> is a semigroup with a <em>neutral element</em>. A
|
||
neutral element is a zero: an element that does nothing when combined
|
||
with other elements. Here are some examples:</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="co">-- 0 is the neutral element of (+)</span></span>
|
||
<span id="cb425-2"><a href="#cb425-2" aria-hidden="true" tabindex="-1"></a><span class="dv">3</span> <span class="op">+</span> <span class="dv">0</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb425-3"><a href="#cb425-3" aria-hidden="true" tabindex="-1"></a><span class="dv">0</span> <span class="op">+</span> <span class="dv">3</span> <span class="op">==></span> <span class="dv">3</span></span>
|
||
<span id="cb425-4"><a href="#cb425-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb425-5"><a href="#cb425-5" aria-hidden="true" tabindex="-1"></a><span class="co">-- 1 is the neutral element of (*)</span></span>
|
||
<span id="cb425-6"><a href="#cb425-6" aria-hidden="true" tabindex="-1"></a><span class="dv">1</span> <span class="op">*</span> <span class="dv">5</span> <span class="op">==></span> <span class="dv">5</span></span>
|
||
<span id="cb425-7"><a href="#cb425-7" aria-hidden="true" tabindex="-1"></a><span class="dv">5</span> <span class="op">*</span> <span class="dv">1</span> <span class="op">==></span> <span class="dv">5</span></span>
|
||
<span id="cb425-8"><a href="#cb425-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb425-9"><a href="#cb425-9" aria-hidden="true" tabindex="-1"></a><span class="co">-- [] is the neutral element of (++)</span></span>
|
||
<span id="cb425-10"><a href="#cb425-10" aria-hidden="true" tabindex="-1"></a>[] <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">2</span>]</span>
|
||
<span id="cb425-11"><a href="#cb425-11" aria-hidden="true" tabindex="-1"></a>[<span class="dv">1</span>,<span class="dv">2</span>] <span class="op">++</span> [] <span class="op">==></span> [<span class="dv">1</span>,<span class="dv">2</span>]</span></code></pre></div>
|
||
<p>The Haskell type class <code>Monoid</code> (from the module
|
||
<code>Data.Monoid</code>) represents monoids.</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">class</span> <span class="dt">Semigroup</span> a <span class="ot">=></span> <span class="dt">Monoid</span> a <span class="kw">where</span></span>
|
||
<span id="cb426-2"><a href="#cb426-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- The neutral element</span></span>
|
||
<span id="cb426-3"><a href="#cb426-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> mempty ::</span> a</span></code></pre></div>
|
||
<p>Here are the <code>Monoid</code> instances corresponding to our three
|
||
examples of neutral elements:</p>
|
||
<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="kw">instance</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Monoid</span> (<span class="dt">Sum</span> a) <span class="kw">where</span></span>
|
||
<span id="cb427-2"><a href="#cb427-2" aria-hidden="true" tabindex="-1"></a> <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Sum</span> <span class="dv">0</span></span>
|
||
<span id="cb427-3"><a href="#cb427-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb427-4"><a href="#cb427-4" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Num</span> a <span class="ot">=></span> <span class="dt">Monoid</span> (<span class="dt">Product</span> a) <span class="kw">where</span></span>
|
||
<span id="cb427-5"><a href="#cb427-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">mempty</span> <span class="ot">=</span> <span class="dt">Product</span> <span class="dv">1</span></span>
|
||
<span id="cb427-6"><a href="#cb427-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb427-7"><a href="#cb427-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">Monoid</span> [] <span class="kw">where</span></span>
|
||
<span id="cb427-8"><a href="#cb427-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">mempty</span> <span class="ot">=</span> []</span></code></pre></div>
|
||
<p>So, what is a monoid for a programmer? A type forms a monoid if
|
||
there’s a way of combining two elements of the type together so that
|
||
parenthesis don’t matter, and there’s a also an “empty element” that can
|
||
be combined with things without changing them. When thought of like
|
||
this, monoids come up in programming quite often!</p>
|
||
<h3 data-number="7.3.4" id="why"><span
|
||
class="header-section-number">7.3.4</span> Why?</h3>
|
||
<p>What use is this <code>Monoid</code> class? Can’t we just write
|
||
<code>1 + 2</code> instead of <code>Sum 1 <> Sum 2</code>? We can,
|
||
yes, but some library functions work on all <code>Monoid</code>
|
||
types.</p>
|
||
<p>The reason we want both a neutral element and an associative binary
|
||
operator is that those are the exact two things we need in order to
|
||
<em>reduce</em> or <em>fold</em> multiple elements into one value. This
|
||
is the job of:</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="fu">mconcat</span><span class="ot"> ::</span> <span class="dt">Monoid</span> a <span class="ot">=></span> [a] <span class="ot">-></span> a</span></code></pre></div>
|
||
<p>Sidenote: one way to define <code>mconcat</code> is
|
||
<code>foldr (<>) mempty</code>. Do you remember
|
||
<code>foldr</code>?</p>
|
||
<p>Let’s look at why we need the properties of <code>Monoid</code> to
|
||
implement <code>mconcat</code>. Firstly, we need <code>mempty</code> to
|
||
handle empty lists:</p>
|
||
<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="fu">mconcat</span> []<span class="ot"> ::</span> <span class="dt">Sum</span> <span class="dt">Int</span> <span class="op">==></span> <span class="dt">Sum</span> <span class="dv">0</span></span></code></pre></div>
|
||
<p>Secondly, we need associativity to be able to reduce a list
|
||
<code>[x,y,z]</code> to a unique value. If <code><></code> were
|
||
not associative, we would have two possible values for
|
||
<code>mconcat [x,y,z]</code>, namely <code>(x<>y)<>z</code>
|
||
and <code>x<>(y<>z)</code>.</p>
|
||
<p>The most useful <code>Monoid</code> function is
|
||
<code>foldMap</code>:</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="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>That type signature looks scary, but concrete cases are simpler:</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="fu">foldMap</span> <span class="dt">Max</span> [<span class="dv">1</span><span class="ot">::</span><span class="dt">Int</span>,<span class="dv">4</span>,<span class="dv">2</span>] <span class="op">==></span> <span class="dt">Max</span> <span class="dv">4</span></span>
|
||
<span id="cb431-2"><a href="#cb431-2" aria-hidden="true" tabindex="-1"></a><span class="fu">foldMap</span> <span class="dt">Product</span> [<span class="dv">1</span><span class="ot">::</span><span class="dt">Int</span>,<span class="dv">4</span>,<span class="dv">2</span>] <span class="op">==></span> <span class="dt">Product</span> <span class="dv">8</span></span>
|
||
<span id="cb431-3"><a href="#cb431-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- We need the ::Int to avoid an "Ambiguous type variable" error when printing the result</span></span></code></pre></div>
|
||
<p>Let’s break down that type. We know that an example of a
|
||
<code>Foldable t => t a</code> type is <code>[a]</code>, so we can
|
||
rewrite the type as</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">foldMap' ::</span> <span class="dt">Monoid</span> m <span class="ot">=></span> (a <span class="ot">-></span> m) <span class="ot">-></span> [a] <span class="ot">-></span> m</span></code></pre></div>
|
||
<p>We can build this function out of functions we already know:</p>
|
||
<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>foldMap' f xs <span class="ot">=</span> <span class="fu">mconcat</span> (<span class="fu">map</span> f xs)</span></code></pre></div>
|
||
<p>Oh, by the way, thanks to the
|
||
<code>(Monoid a, Monoid b) => Monoid (a,b)</code> instance we can
|
||
even compute the maximum and product in one pass:</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="fu">foldMap</span> (\x <span class="ot">-></span> (<span class="dt">Max</span> x, <span class="dt">Product</span> x)) [<span class="dv">1</span><span class="ot">::</span><span class="dt">Int</span>,<span class="dv">4</span>,<span class="dv">2</span>] <span class="op">==></span> (<span class="dt">Max</span> <span class="dv">4</span>, <span class="dt">Product</span> <span class="dv">8</span>)</span></code></pre></div>
|
||
<p>Note, you don’t need to use monoids in your own code, but you’ll
|
||
eventually bump into them when using Haskell libraries so it’s good to
|
||
know what they are.</p>
|
||
<h3 data-number="7.3.5" id="how"><span
|
||
class="header-section-number">7.3.5</span> How?</h3>
|
||
<p>Due to various historical and performance reasons, the definition of
|
||
the <code>Monoid</code> and <code>Semigroup</code> classes aren’t
|
||
just</p>
|
||
<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="kw">class</span> <span class="dt">Semigroup</span> a <span class="kw">where</span></span>
|
||
<span id="cb435-2"><a href="#cb435-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<>) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb435-3"><a href="#cb435-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> <span class="dt">Semigroup</span> a <span class="ot">=></span> <span class="dt">Monoid</span> a <span class="kw">where</span></span>
|
||
<span id="cb435-4"><a href="#cb435-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> mempty ::</span> a</span></code></pre></div>
|
||
<p>Although you can mostly pretend they are. The actual definitions
|
||
are:</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="kw">class</span> <span class="dt">Semigroup</span> a <span class="kw">where</span></span>
|
||
<span id="cb436-2"><a href="#cb436-2" aria-hidden="true" tabindex="-1"></a> <span class="co">-- | An associative operation.</span></span>
|
||
<span id="cb436-3"><a href="#cb436-3" aria-hidden="true" tabindex="-1"></a><span class="ot"> (<>) ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb436-4"><a href="#cb436-4" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb436-5"><a href="#cb436-5" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Combine elements of a nonempty list with <></span></span>
|
||
<span id="cb436-6"><a href="#cb436-6" aria-hidden="true" tabindex="-1"></a><span class="ot"> sconcat ::</span> <span class="dt">NonEmpty</span> a <span class="ot">-></span> a</span>
|
||
<span id="cb436-7"><a href="#cb436-7" aria-hidden="true" tabindex="-1"></a> sconcat as <span class="ot">=</span> <span class="op">...</span> <span class="co">-- default implementation omitted</span></span>
|
||
<span id="cb436-8"><a href="#cb436-8" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb436-9"><a href="#cb436-9" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Combine a value with itself using <>, n times</span></span>
|
||
<span id="cb436-10"><a href="#cb436-10" aria-hidden="true" tabindex="-1"></a><span class="ot"> stimes ::</span> <span class="dt">Integral</span> b <span class="ot">=></span> b <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb436-11"><a href="#cb436-11" aria-hidden="true" tabindex="-1"></a> stimes n x <span class="ot">=</span> <span class="op">...</span> <span class="co">-- default implementation omitted</span></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="kw">class</span> <span class="dt">Semigroup</span> a <span class="ot">=></span> <span class="dt">Monoid</span> a <span class="kw">where</span></span>
|
||
<span id="cb437-2"><a href="#cb437-2" aria-hidden="true" tabindex="-1"></a><span class="ot"> mempty ::</span> a</span>
|
||
<span id="cb437-3"><a href="#cb437-3" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb437-4"><a href="#cb437-4" aria-hidden="true" tabindex="-1"></a><span class="ot"> mappend ::</span> a <span class="ot">-></span> a <span class="ot">-></span> a</span>
|
||
<span id="cb437-5"><a href="#cb437-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">mappend</span> <span class="ot">=</span> (<span class="op"><></span>)</span>
|
||
<span id="cb437-6"><a href="#cb437-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb437-7"><a href="#cb437-7" aria-hidden="true" tabindex="-1"></a> <span class="co">-- Combine elements of a list with <></span></span>
|
||
<span id="cb437-8"><a href="#cb437-8" aria-hidden="true" tabindex="-1"></a><span class="ot"> mconcat ::</span> [a] <span class="ot">-></span> a</span>
|
||
<span id="cb437-9"><a href="#cb437-9" aria-hidden="true" tabindex="-1"></a> <span class="fu">mconcat</span> <span class="ot">=</span> <span class="op">...</span> <span class="co">-- default implementation omitted</span></span></code></pre></div>
|
||
<p>As you can see, all the operations except <code><></code> and
|
||
<code>mempty</code> have default definitions, so a normal
|
||
<code>Monoid</code> instance declaration looks just like this:</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">instance</span> <span class="dt">Semigroup</span> <span class="dt">MyType</span> <span class="kw">where</span></span>
|
||
<span id="cb438-2"><a href="#cb438-2" aria-hidden="true" tabindex="-1"></a> x <span class="op"><></span> y <span class="ot">=</span> <span class="op">...</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="kw">instance</span> <span class="dt">Monoid</span> <span class="dt">MyType</span> <span class="kw">where</span></span>
|
||
<span id="cb438-5"><a href="#cb438-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">mempty</span> <span class="ot">=</span> <span class="op">...</span></span></code></pre></div>
|
||
<h2 data-number="7.4" id="open-and-closed-abstractions"><span
|
||
class="header-section-number">7.4</span> Open and Closed
|
||
Abstractions</h2>
|
||
<p>A question novice Haskell programmers often ask (or at least should
|
||
ask!) is: when should I use type classes? This section offers one
|
||
answer.</p>
|
||
<p>Let’s look at a concrete example. A vehicle can be either a car or an
|
||
airplane. We can model this with algebraic datatypes (as we’ve seen
|
||
earlier in this chapter), but also with type classes. Here’s the
|
||
datatype version:</p>
|
||
<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="kw">data</span> <span class="dt">Vehicle</span> <span class="ot">=</span> <span class="dt">Car</span> <span class="dt">String</span> <span class="op">|</span> <span class="dt">Airplane</span> <span class="dt">String</span></span>
|
||
<span id="cb439-2"><a href="#cb439-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb439-3"><a href="#cb439-3" aria-hidden="true" tabindex="-1"></a><span class="ot">sound ::</span> <span class="dt">Vehicle</span> <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb439-4"><a href="#cb439-4" aria-hidden="true" tabindex="-1"></a>sound (<span class="dt">Car</span> _) <span class="ot">=</span> <span class="st">"brum brum"</span></span>
|
||
<span id="cb439-5"><a href="#cb439-5" aria-hidden="true" tabindex="-1"></a>sound (<span class="dt">Airplane</span> _) <span class="ot">=</span> <span class="st">"zooooom"</span></span></code></pre></div>
|
||
<p>Here’s the class version. Note how each case gets its own datatype,
|
||
which are collected together in a type class.</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">Car</span> <span class="ot">=</span> <span class="dt">Car</span> <span class="dt">String</span></span>
|
||
<span id="cb440-2"><a href="#cb440-2" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Airplane</span> <span class="ot">=</span> <span class="dt">Airplane</span> <span class="dt">String</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">class</span> <span class="dt">VehicleClass</span> a <span class="kw">where</span></span>
|
||
<span id="cb440-5"><a href="#cb440-5" aria-hidden="true" tabindex="-1"></a><span class="ot"> sound ::</span> a <span class="ot">-></span> <span class="dt">String</span></span>
|
||
<span id="cb440-6"><a href="#cb440-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-7"><a href="#cb440-7" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">VehicleClass</span> <span class="dt">Car</span> <span class="kw">where</span></span>
|
||
<span id="cb440-8"><a href="#cb440-8" aria-hidden="true" tabindex="-1"></a> sound (<span class="dt">Car</span> _) <span class="ot">=</span> <span class="st">"brum brum"</span></span>
|
||
<span id="cb440-9"><a href="#cb440-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb440-10"><a href="#cb440-10" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">VehicleClass</span> <span class="dt">Airplane</span> <span class="kw">where</span></span>
|
||
<span id="cb440-11"><a href="#cb440-11" aria-hidden="true" tabindex="-1"></a> sound (<span class="dt">Airplane</span> _) <span class="ot">=</span> <span class="st">"zooooom"</span></span></code></pre></div>
|
||
<p>What is the difference between these solutions? The data-based
|
||
solution is <em>closed</em>, meaning the set of cases is fixed and we
|
||
can handle all of them in one place. The class-based solution is
|
||
<em>open</em>, meaning we can add new cases, even in other modules.</p>
|
||
<p>An open abstraction is nice when we want extensibility. In the
|
||
class-based solution, another module could define a bike:</p>
|
||
<div class="sourceCode" id="cb441"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb441-1"><a href="#cb441-1" aria-hidden="true" tabindex="-1"></a><span class="kw">data</span> <span class="dt">Bike</span> <span class="ot">=</span> <span class="dt">Bike</span> <span class="dt">String</span></span>
|
||
<span id="cb441-2"><a href="#cb441-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb441-3"><a href="#cb441-3" aria-hidden="true" tabindex="-1"></a><span class="kw">instance</span> <span class="dt">VehicleClass</span> <span class="dt">Bike</span> <span class="kw">where</span></span>
|
||
<span id="cb441-4"><a href="#cb441-4" aria-hidden="true" tabindex="-1"></a> sound (<span class="dt">Bike</span> _) <span class="ot">=</span> <span class="st">"whirrr"</span></span></code></pre></div>
|
||
<p>A closed abstraction is good when we want to know that we’ve handled
|
||
all cases, consider for example the function <code>canCollide</code>
|
||
which checks whether two vehicles can collide:</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="ot">canCollide ::</span> <span class="dt">Vehicle</span> <span class="ot">-></span> <span class="dt">Vehicle</span> <span class="ot">-></span> <span class="dt">Bool</span></span>
|
||
<span id="cb442-2"><a href="#cb442-2" aria-hidden="true" tabindex="-1"></a>canCollide (<span class="dt">Car</span> _) (<span class="dt">Car</span> _) <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb442-3"><a href="#cb442-3" aria-hidden="true" tabindex="-1"></a>canCollide (<span class="dt">Airplane</span> _) (<span class="dt">Airplane</span> _) <span class="ot">=</span> <span class="dt">True</span></span>
|
||
<span id="cb442-4"><a href="#cb442-4" aria-hidden="true" tabindex="-1"></a>canCollide _ _ <span class="ot">=</span> <span class="dt">False</span></span></code></pre></div>
|
||
<p>This would be very hard to implement reliably in the class-based
|
||
solution. Consider for example how collision checks between
|
||
<code>Bike</code>s and <code>Car</code>s would get handled.</p>
|
||
<h2 data-number="7.5" id="modeling-with-languages"><span
|
||
class="header-section-number">7.5</span> Modeling with Languages</h2>
|
||
<p>Sometimes it’s useful to implement a mini programming language for
|
||
describing parts of your software. The fancy term for these is an
|
||
<em>Embedded Domain-Specific Language (EDSL)</em>. Haskell is well
|
||
suited to modeling and interpreting languages. The expressions of the
|
||
language are represented using (often recursive) algebraic data types.
|
||
The language can be <em>interpreted</em> (that is, evaluated or run) by
|
||
a recursive function.</p>
|
||
<p>Here’s an example of a language for describing price computations for
|
||
products in a web shop.</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="kw">data</span> <span class="dt">Discount</span> <span class="ot">=</span> <span class="dt">DiscountPercent</span> <span class="dt">Int</span> <span class="co">-- A percentage discount</span></span>
|
||
<span id="cb443-2"><a href="#cb443-2" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">DiscountConstant</span> <span class="dt">Int</span> <span class="co">-- A constant discount</span></span>
|
||
<span id="cb443-3"><a href="#cb443-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">MinimumPrice</span> <span class="dt">Int</span> <span class="co">-- Set a minimum price</span></span>
|
||
<span id="cb443-4"><a href="#cb443-4" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">ForCustomer</span> <span class="dt">String</span> <span class="dt">Discount</span> <span class="co">-- Discounts can be conditional</span></span>
|
||
<span id="cb443-5"><a href="#cb443-5" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Many</span> [<span class="dt">Discount</span>] <span class="co">-- Apply a number of discounts in row</span></span></code></pre></div>
|
||
<p>The language is interpreted by the function
|
||
<code>applyDiscount</code> that takes a customer name, a price, a
|
||
discount, and returns a price.</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">applyDiscount ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Discount</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb444-2"><a href="#cb444-2" aria-hidden="true" tabindex="-1"></a>applyDiscount _ price (<span class="dt">DiscountPercent</span> percent) <span class="ot">=</span> price <span class="op">-</span> (price <span class="op">*</span> percent) <span class="ot">`div`</span> <span class="dv">100</span></span>
|
||
<span id="cb444-3"><a href="#cb444-3" aria-hidden="true" tabindex="-1"></a>applyDiscount _ price (<span class="dt">DiscountConstant</span> discount) <span class="ot">=</span> price <span class="op">-</span> discount</span>
|
||
<span id="cb444-4"><a href="#cb444-4" aria-hidden="true" tabindex="-1"></a>applyDiscount _ price (<span class="dt">MinimumPrice</span> minPrice) <span class="ot">=</span> <span class="fu">max</span> price minPrice</span>
|
||
<span id="cb444-5"><a href="#cb444-5" aria-hidden="true" tabindex="-1"></a>applyDiscount customer price (<span class="dt">ForCustomer</span> target discount)</span>
|
||
<span id="cb444-6"><a href="#cb444-6" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> customer <span class="op">==</span> target <span class="ot">=</span> applyDiscount customer price discount</span>
|
||
<span id="cb444-7"><a href="#cb444-7" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="fu">otherwise</span> <span class="ot">=</span> price</span>
|
||
<span id="cb444-8"><a href="#cb444-8" aria-hidden="true" tabindex="-1"></a>applyDiscount customer price (<span class="dt">Many</span> discounts) <span class="ot">=</span> go price discounts</span>
|
||
<span id="cb444-9"><a href="#cb444-9" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> go p [] <span class="ot">=</span> p</span>
|
||
<span id="cb444-10"><a href="#cb444-10" aria-hidden="true" tabindex="-1"></a> go p (d<span class="op">:</span>ds) <span class="ot">=</span> go (applyDiscount customer p d) ds</span></code></pre></div>
|
||
<p>Here we apply a discount chain of -50%, -$30 with a minimum price of
|
||
$35:</p>
|
||
<div class="sourceCode" id="cb445"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb445-1"><a href="#cb445-1" aria-hidden="true" tabindex="-1"></a>applyDiscount <span class="st">"Bob"</span> <span class="dv">120</span> (<span class="dt">DiscountPercent</span> <span class="dv">50</span>)</span>
|
||
<span id="cb445-2"><a href="#cb445-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">60</span></span>
|
||
<span id="cb445-3"><a href="#cb445-3" aria-hidden="true" tabindex="-1"></a>applyDiscount <span class="st">"Bob"</span> <span class="dv">60</span> (<span class="dt">DiscountConstant</span> <span class="dv">30</span>)</span>
|
||
<span id="cb445-4"><a href="#cb445-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">30</span></span>
|
||
<span id="cb445-5"><a href="#cb445-5" aria-hidden="true" tabindex="-1"></a>applyDiscount <span class="st">"Bob"</span> <span class="dv">30</span> (<span class="dt">MinimumPrice</span> <span class="dv">35</span>)</span>
|
||
<span id="cb445-6"><a href="#cb445-6" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">35</span></span>
|
||
<span id="cb445-7"><a href="#cb445-7" aria-hidden="true" tabindex="-1"></a>applyDiscount <span class="st">"Bob"</span> <span class="dv">120</span> (<span class="dt">Many</span> [<span class="dt">DiscountPercent</span> <span class="dv">50</span>, <span class="dt">DiscountConstant</span> <span class="dv">30</span>, <span class="dt">MinimumPrice</span> <span class="dv">35</span>])</span>
|
||
<span id="cb445-8"><a href="#cb445-8" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">35</span></span></code></pre></div>
|
||
<p>Here we have different discounts for Ssarah and Yvonne:</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>applyDiscount <span class="st">"Yvonne"</span> <span class="dv">100</span> (<span class="dt">Many</span> [<span class="dt">ForCustomer</span> <span class="st">"Yvonne"</span> (<span class="dt">DiscountConstant</span> <span class="dv">10</span>), <span class="dt">ForCustomer</span> <span class="st">"Ssarah"</span> (<span class="dt">DiscountConstant</span> <span class="dv">20</span>)])</span>
|
||
<span id="cb446-2"><a href="#cb446-2" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">90</span></span>
|
||
<span id="cb446-3"><a href="#cb446-3" aria-hidden="true" tabindex="-1"></a>applyDiscount <span class="st">"Ssarah"</span> <span class="dv">100</span> (<span class="dt">Many</span> [<span class="dt">ForCustomer</span> <span class="st">"Yvonne"</span> (<span class="dt">DiscountConstant</span> <span class="dv">10</span>), <span class="dt">ForCustomer</span> <span class="st">"Ssarah"</span> (<span class="dt">DiscountConstant</span> <span class="dv">20</span>)])</span>
|
||
<span id="cb446-4"><a href="#cb446-4" aria-hidden="true" tabindex="-1"></a> <span class="op">==></span> <span class="dv">80</span></span></code></pre></div>
|
||
<p>As you can see, even a simple <code>Discount</code> type can generate
|
||
complex behaviours because it is self-referential (recursive). Using
|
||
<code>Discount</code> we are able to represent the discount logic of our
|
||
webshop as <em>data</em> instead of writing code.</p>
|
||
<p>There are multiple reasons for representing logic as data instead of
|
||
code. Unlike code, data can easily be stored in a file or database, or
|
||
even transmitted over the network. We can also use the same data for
|
||
multiple purposes, for example we could visualize the discount rules in
|
||
an administration user interface.</p>
|
||
<!-- ## TODO: Quiz -->
|
||
<h2 data-number="7.6" id="exercises-6"><span
|
||
class="header-section-number">7.6</span> Exercises</h2>
|
||
<ul>
|
||
<li><a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set7.hs">Set7</a></li>
|
||
</ul>
|
||
<h1 data-number="8" id="lecture-8-the-aftertaste"><span
|
||
class="header-section-number">8</span> Lecture 8: The Aftertaste</h1>
|
||
<h2 data-number="8.1" id="a-taste-of-io"><span
|
||
class="header-section-number">8.1</span> A Taste of IO</h2>
|
||
<p>This course has been centered around pure functional programming.
|
||
We’ve done lots of arithmetic, reversed lists, worked with binary trees,
|
||
but so far we haven’t been able to affect the world outside our
|
||
GHCi.</p>
|
||
<p>Things like reading input, writing to a file, or talking over the
|
||
network are <em>side effects</em>. Side effects can’t be represented
|
||
with pure functional code. A function like</p>
|
||
<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">readInputFromTheUser ::</span> <span class="dt">String</span> <span class="ot">-></span> <span class="dt">String</span></span></code></pre></div>
|
||
<p>can’t be pure, because if it were,
|
||
<code>readInputFromUser "What is your name?"</code> would always have to
|
||
return the same result. However, representing side-effects and impurity
|
||
in a pure language <em>is</em> possible. There are many ways of doing
|
||
it, and the Haskell way is to use <em>Monads</em>.</p>
|
||
<p>Monads are reputedly difficult to understand. That is probably
|
||
because they are so abstract. I think it’s best to focus on practical
|
||
and concrete cases first. Here’s a taste of the <code>IO</code> Monad,
|
||
which you can use for all sorts of side effects in Haskell.</p>
|
||
<p>Let’s start!</p>
|
||
<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="op">></span> <span class="op">:</span>t <span class="fu">getLine</span></span>
|
||
<span id="cb448-2"><a href="#cb448-2" 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="cb448-3"><a href="#cb448-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> line <span class="ot"><-</span> <span class="fu">getLine</span></span></code></pre></div>
|
||
<pre><code>another line</code></pre>
|
||
<div class="sourceCode" id="cb450"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb450-1"><a href="#cb450-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t line</span>
|
||
<span id="cb450-2"><a href="#cb450-2" aria-hidden="true" tabindex="-1"></a><span class="ot">line ::</span> <span class="dt">String</span></span>
|
||
<span id="cb450-3"><a href="#cb450-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> line</span>
|
||
<span id="cb450-4"><a href="#cb450-4" aria-hidden="true" tabindex="-1"></a><span class="st">"another line"</span></span>
|
||
<span id="cb450-5"><a href="#cb450-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">reverse</span> line</span>
|
||
<span id="cb450-6"><a href="#cb450-6" aria-hidden="true" tabindex="-1"></a><span class="st">"enil rehtona"</span></span></code></pre></div>
|
||
<p>What we’ve seen here is the <em>IO action</em> <code>getLine</code>.
|
||
It has type <code>IO String</code>. This means that GHCi can
|
||
<em>execute</em> the action to produce a value of type
|
||
<code>String</code>. When we enter <code>line <- getLine</code> into
|
||
GHCi, we mean:</p>
|
||
<blockquote>
|
||
<p>Execute the IO action <code>getLine</code>, and give the result the
|
||
name <code>line</code>.</p>
|
||
</blockquote>
|
||
<p>After we’ve received <code>line</code>, it’s a pure
|
||
<code>String</code> value and we can work with it normally.</p>
|
||
<p>Some IO actions take parameters. For example
|
||
<code>putStrLn :: String -> IO ()</code> takes a <code>String</code>
|
||
and returns an <code>IO</code> action that prints that string. The
|
||
<code>()</code> type is a special type that only has one value,
|
||
<code>()</code>. In this case <code>IO ()</code> means that this IO
|
||
always produces the same empty value <code>()</code>. You can run IO
|
||
actions by just</p>
|
||
<div class="sourceCode" id="cb451"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb451-1"><a href="#cb451-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="cb451-2"><a href="#cb451-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="cb451-3"><a href="#cb451-3" 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 class="st">"hello"</span></span>
|
||
<span id="cb451-4"><a href="#cb451-4" aria-hidden="true" tabindex="-1"></a><span class="fu">putStrLn</span> <span class="st">"hello"</span><span class="ot"> ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb451-5"><a href="#cb451-5" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> val <span class="ot"><-</span> <span class="fu">putStrLn</span> <span class="st">"hello"</span></span>
|
||
<span id="cb451-6"><a href="#cb451-6" aria-hidden="true" tabindex="-1"></a>hello</span>
|
||
<span id="cb451-7"><a href="#cb451-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> val</span>
|
||
<span id="cb451-8"><a href="#cb451-8" aria-hidden="true" tabindex="-1"></a>()</span></code></pre></div>
|
||
<p>If you don’t need the return value of an IO action, you can run it
|
||
<em>in GHCi</em> without the <code><-</code>:</p>
|
||
<div class="sourceCode" id="cb452"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb452-1"><a href="#cb452-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">putStrLn</span> <span class="st">"hello"</span></span>
|
||
<span id="cb452-2"><a href="#cb452-2" aria-hidden="true" tabindex="-1"></a>hello</span></code></pre></div>
|
||
<p>You can build your own IO actions by combining other actions with
|
||
<em>do-notation</em>. A <code>do</code> block lists IO actions that are
|
||
executed in order.</p>
|
||
<div class="sourceCode" id="cb453"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb453-1"><a href="#cb453-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printTwoThings ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb453-2"><a href="#cb453-2" aria-hidden="true" tabindex="-1"></a>printTwoThings <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb453-3"><a href="#cb453-3" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"Hello!"</span></span>
|
||
<span id="cb453-4"><a href="#cb453-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"How are you?"</span></span>
|
||
<span id="cb453-5"><a href="#cb453-5" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb453-6"><a href="#cb453-6" aria-hidden="true" tabindex="-1"></a><span class="ot">greet ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb453-7"><a href="#cb453-7" aria-hidden="true" tabindex="-1"></a>greet <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb453-8"><a href="#cb453-8" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> <span class="st">"What's your name?"</span></span>
|
||
<span id="cb453-9"><a href="#cb453-9" aria-hidden="true" tabindex="-1"></a> name <span class="ot"><-</span> <span class="fu">getLine</span></span>
|
||
<span id="cb453-10"><a href="#cb453-10" aria-hidden="true" tabindex="-1"></a> <span class="fu">putStrLn</span> (<span class="st">"Hello, "</span> <span class="op">++</span> name)</span></code></pre></div>
|
||
<div class="sourceCode" id="cb454"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb454-1"><a href="#cb454-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> printTwoThings</span>
|
||
<span id="cb454-2"><a href="#cb454-2" aria-hidden="true" tabindex="-1"></a><span class="dt">Hello</span><span class="op">!</span></span>
|
||
<span id="cb454-3"><a href="#cb454-3" aria-hidden="true" tabindex="-1"></a><span class="dt">How</span> are you<span class="op">?</span></span>
|
||
<span id="cb454-4"><a href="#cb454-4" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> greet</span>
|
||
<span id="cb454-5"><a href="#cb454-5" aria-hidden="true" tabindex="-1"></a><span class="dt">What's</span> your name<span class="op">?</span></span>
|
||
<span id="cb454-6"><a href="#cb454-6" aria-hidden="true" tabindex="-1"></a><span class="dt">Seraphim</span></span>
|
||
<span id="cb454-7"><a href="#cb454-7" aria-hidden="true" tabindex="-1"></a><span class="dt">Hello</span>, <span class="dt">Seraphim</span></span></code></pre></div>
|
||
<h3 data-number="8.1.1" id="what-about-purity"><span
|
||
class="header-section-number">8.1.1</span> What About Purity?</h3>
|
||
<p>It feels as if we can just do side effects where ever we want with
|
||
these IO actions. However, it’s important to remember the distinction
|
||
between <em>defining</em> an IO action and <em>executing</em> it.</p>
|
||
<p>Let’s try to print while mapping over a list</p>
|
||
<div class="sourceCode" id="cb455"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb455-1"><a href="#cb455-1" aria-hidden="true" tabindex="-1"></a><span class="ot">printAndIncrement ::</span> <span class="dt">Int</span> <span class="ot">-></span> <span class="dt">Int</span></span>
|
||
<span id="cb455-2"><a href="#cb455-2" aria-hidden="true" tabindex="-1"></a>printAndIncrement x <span class="ot">=</span> x<span class="op">+</span><span class="dv">1</span></span>
|
||
<span id="cb455-3"><a href="#cb455-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">where</span> action <span class="ot">=</span> <span class="fu">putStrLn</span> <span class="st">"got a number!"</span></span></code></pre></div>
|
||
<div class="sourceCode" id="cb456"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb456-1"><a href="#cb456-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">map</span> printAndIncrement [<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>]</span>
|
||
<span id="cb456-2"><a href="#cb456-2" aria-hidden="true" tabindex="-1"></a>[<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>]</span></code></pre></div>
|
||
<p>This didn’t print anything, because even though we defined our
|
||
<code>action</code>, it wasn’t given to GHCi for execution. Because
|
||
<code>printAndIncrement</code> returns an <code>Int</code>, it can’t
|
||
return an action. Ok, let’s try another approach:</p>
|
||
<div class="sourceCode" id="cb457"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb457-1"><a href="#cb457-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">length</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])</span>
|
||
<span id="cb457-2"><a href="#cb457-2" aria-hidden="true" tabindex="-1"></a><span class="dv">2</span></span></code></pre></div>
|
||
<p>That didn’t print anything either! Let’s see why:</p>
|
||
<div class="sourceCode" id="cb458"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb458-1"><a href="#cb458-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>]</span>
|
||
<span id="cb458-2"><a href="#cb458-2" aria-hidden="true" tabindex="-1"></a><span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>]<span class="ot"> ::</span> [<span class="dt">IO</span> ()]</span>
|
||
<span id="cb458-3"><a href="#cb458-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">length</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])</span>
|
||
<span id="cb458-4"><a href="#cb458-4" aria-hidden="true" tabindex="-1"></a><span class="fu">length</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])<span class="ot"> ::</span> <span class="dt">Int</span></span></code></pre></div>
|
||
<p>We generated a list of IO actions and computed the length of the
|
||
list. Defining IO actions is pure, it’s <em>running</em> them that
|
||
causes side effects. Since the type of our expression was
|
||
<code>Int</code>, no <code>IO</code> actions could land in GHCi and be
|
||
executed.</p>
|
||
<p>If we instead return an IO action, it does get run:</p>
|
||
<div class="sourceCode" id="cb459"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb459-1"><a href="#cb459-1" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="op">:</span>t <span class="fu">head</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])</span>
|
||
<span id="cb459-2"><a href="#cb459-2" aria-hidden="true" tabindex="-1"></a><span class="fu">head</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])<span class="ot"> ::</span> <span class="dt">IO</span> ()</span>
|
||
<span id="cb459-3"><a href="#cb459-3" aria-hidden="true" tabindex="-1"></a><span class="dt">Prelude</span><span class="op">></span> <span class="fu">head</span> (<span class="fu">map</span> <span class="fu">putStrLn</span> [<span class="st">"string1"</span>,<span class="st">"string2"</span>])</span>
|
||
<span id="cb459-4"><a href="#cb459-4" aria-hidden="true" tabindex="-1"></a>string1</span></code></pre></div>
|
||
<p>Here too, the code that produces the action
|
||
<code>putStrLn "string1"</code> is pure, it’s only after the IO action
|
||
is executed by GHCi that we see the printed string. And as you can see,
|
||
the other IO action, <code>putStrLn "string2"</code>, never got run.</p>
|
||
<p>If this feels complicated, don’t worry. We’ll get back to this on
|
||
part 2 of the course.</p>
|
||
<h3 data-number="8.1.2" id="what-about-haskell-programs"><span
|
||
class="header-section-number">8.1.2</span> What About Haskell
|
||
Programs?</h3>
|
||
<p>We know that GHCi can run IO actions. What about actual Haskell
|
||
programs? The way Haskell programs work is that the IO action called
|
||
<code>main</code> gets executed when the program is run. Recall our
|
||
example program from Lecture 1.</p>
|
||
<div class="sourceCode" id="cb460"><pre
|
||
class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb460-1"><a href="#cb460-1" aria-hidden="true" tabindex="-1"></a><span class="kw">module</span> <span class="dt">Gold</span> <span class="kw">where</span></span>
|
||
<span id="cb460-2"><a href="#cb460-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb460-3"><a href="#cb460-3" aria-hidden="true" tabindex="-1"></a><span class="co">-- The golden ratio</span></span>
|
||
<span id="cb460-4"><a href="#cb460-4" aria-hidden="true" tabindex="-1"></a><span class="ot">phi ::</span> <span class="dt">Double</span></span>
|
||
<span id="cb460-5"><a href="#cb460-5" aria-hidden="true" tabindex="-1"></a>phi <span class="ot">=</span> (<span class="fu">sqrt</span> <span class="dv">5</span> <span class="op">+</span> <span class="dv">1</span>) <span class="op">/</span> <span class="dv">2</span></span>
|
||
<span id="cb460-6"><a href="#cb460-6" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb460-7"><a href="#cb460-7" aria-hidden="true" tabindex="-1"></a><span class="ot">polynomial ::</span> <span class="dt">Double</span> <span class="ot">-></span> <span class="dt">Double</span></span>
|
||
<span id="cb460-8"><a href="#cb460-8" aria-hidden="true" tabindex="-1"></a>polynomial x <span class="ot">=</span> x<span class="op">^</span><span class="dv">2</span> <span class="op">-</span> x <span class="op">-</span> <span class="dv">1</span></span>
|
||
<span id="cb460-9"><a href="#cb460-9" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb460-10"><a href="#cb460-10" aria-hidden="true" tabindex="-1"></a>f x <span class="ot">=</span> polynomial (polynomial x)</span>
|
||
<span id="cb460-11"><a href="#cb460-11" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb460-12"><a href="#cb460-12" aria-hidden="true" tabindex="-1"></a>main <span class="ot">=</span> <span class="kw">do</span></span>
|
||
<span id="cb460-13"><a href="#cb460-13" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (polynomial phi)</span>
|
||
<span id="cb460-14"><a href="#cb460-14" aria-hidden="true" tabindex="-1"></a> <span class="fu">print</span> (f phi)</span></code></pre></div>
|
||
<p>Here we see some pure code and a <code>main</code> IO action that
|
||
prints two things (<code>print</code> is just <code>putStrLn</code>
|
||
combined with <code>show</code>).</p>
|
||
<p>We can place this code in a file called <code>Gold.hs</code>, compile
|
||
it into an executable, and run it:</p>
|
||
<div class="sourceCode" id="cb461"><pre
|
||
class="sourceCode sh"><code class="sourceCode bash"><span id="cb461-1"><a href="#cb461-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ghc <span class="at">-main-is</span> Gold Gold.hs</span>
|
||
<span id="cb461-2"><a href="#cb461-2" aria-hidden="true" tabindex="-1"></a><span class="ex">[1</span> of 1] Compiling Gold <span class="er">(</span> <span class="ex">Gold.hs,</span> Gold.o <span class="kw">)</span></span>
|
||
<span id="cb461-3"><a href="#cb461-3" aria-hidden="true" tabindex="-1"></a><span class="ex">Linking</span> Gold ...</span>
|
||
<span id="cb461-4"><a href="#cb461-4" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> ./Gold</span>
|
||
<span id="cb461-5"><a href="#cb461-5" aria-hidden="true" tabindex="-1"></a><span class="ex">0.0</span></span>
|
||
<span id="cb461-6"><a href="#cb461-6" aria-hidden="true" tabindex="-1"></a><span class="ex">-1.0</span></span></code></pre></div>
|
||
<h2 data-number="8.2" id="summary"><span
|
||
class="header-section-number">8.2</span> Summary</h2>
|
||
<p>So far, we’ve learned about Haskell’s syntax and types, quite a bit
|
||
of functional programming and about some language features like type
|
||
classes.</p>
|
||
<p>We’ve also seen some type-oriented programming, and even gotten a
|
||
taste of I/O in Haskell.</p>
|
||
<p>Now you know how to write a real computer program in Haskell, but
|
||
there’s still much to learn.</p>
|
||
<h2 data-number="8.3" id="what-next"><span
|
||
class="header-section-number">8.3</span> What Next?</h2>
|
||
<p><a href="https://haskell.mooc.fi/part2">Part 2 of the course</a> is
|
||
now out! Part 2 will cover topics like Monads, IO and how Haskell works
|
||
under the hood. We’ll also get to do some real world programming with
|
||
networks and databases. Oh and testing in Haskell is also covered.</p>
|
||
<p>If you don’t feel like jumping into part 2 right now, here are some
|
||
other Haskell resources you should be able to follow now:</p>
|
||
<ul>
|
||
<li><a href="https://book.realworldhaskell.org/read/">Real World
|
||
Haskell</a> - free e-book on advanced topics</li>
|
||
<li><a
|
||
href="https://web.archive.org/web/20220513191346/http://dev.stephendiehl.com/hask/">What
|
||
I Wish I Knew When Learning Haskell</a></li>
|
||
<li><a href="https://en.wikibooks.org/wiki/Haskell">The Haskell
|
||
Wikibook</a></li>
|
||
<li><a href="https://www.haskell.org/">The Haskell Website</a> has links
|
||
to talks and presentations</li>
|
||
<li><a
|
||
href="https://kowainik.github.io/posts/haskell-mini-patterns">Haskell
|
||
mini-patterns handbook</a> - more stuff like Lecture 7</li>
|
||
</ul>
|
||
<p>I also recommend working on some programming problems in Haskell,
|
||
like the ones from:</p>
|
||
<ul>
|
||
<li><a href="https://adventofcode.com/2019/events">Advent of Code</a> –
|
||
nice varying puzzles, start off easy and get harder</li>
|
||
<li><a href="https://www.spoj.com/">Sphere Online Judge</a> – algorithm
|
||
problems, good variety of difficulties</li>
|
||
<li><a href="https://projecteuler.net/">Project Euler</a> – mathematical
|
||
programming puzzles</li>
|
||
</ul>
|
||
<p>You can also keep extending your final project and maybe generate
|
||
some cool art in Haskell.</p>
|
||
<p>In any case – thank you so much for tagging along, and we hope you
|
||
have a great rest of the year!</p>
|
||
<h2 data-number="8.4" id="final-project-graphics"><span
|
||
class="header-section-number">8.4</span> Final Project: Graphics</h2>
|
||
<p>Open up the exercise file <a
|
||
href="https://github.com/moocfi/haskell-mooc/blob/master/exercises/Set8.hs"><code>Set8.hs</code></a>
|
||
and follow the instructions there. Have fun!</p>
|
||
<h2 data-number="8.5" id="acknowledgements"><span
|
||
class="header-section-number">8.5</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! Check out our <a
|
||
href="https://www.nitor.com/en/jobs">open positions</a> if you’re
|
||
interested in working somewhere that values continuous learning.</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>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</body>
|
||
</html>
|