0% found this document useful (0 votes)
25 views587 pages

A Type of Programming

The document is an unfinished draft by Renzo Carbonara from September 2019, outlining various topics related to programming and computer science. It includes a comprehensive table of contents with 73 sections covering subjects such as computers, machines, programs, types, and various programming concepts. The draft appears to be a detailed exploration of programming principles and methodologies.

Uploaded by

siva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views587 pages

A Type of Programming

The document is an unfinished draft by Renzo Carbonara from September 2019, outlining various topics related to programming and computer science. It includes a comprehensive table of contents with 73 sections covering subjects such as computers, machines, programs, types, and various programming concepts. The draft appears to be a detailed exploration of programming principles and methodologies.

Uploaded by

siva
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 587

A Type of Programming

UNFINISHED DRAFT — September 2019

Renzo Carbonara
Table of Contents
1. Computers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2. Dare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3. Machines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
4. Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
5. Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
6. Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
7. Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
8. Runtime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
9. Function application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
10. Perspective . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
11. β-reduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
12. Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
13. Datatypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
14. Pattern matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
15. Exhaustiveness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
16. Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
17. Parsing. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
18. Either . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
19. Isomorphisms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
20. Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
21. Dos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
22. Tuple syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
23. Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
24. Induction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
25. Representation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
26. Halt!. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
27. Too much . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
28. λ-calculus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
29. List syntax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
30. Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
31. η-conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
32. Partial application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
33. Bliss . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
34. Typeclass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
35. Functor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
36. Instances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
37. Parametricity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
38. Law . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
39. Composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
40. Polymorphic composition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
41. Second functor law . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
42. Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
43. Fixity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
44. List constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
45. Abstraction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
46. Functor f. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
47. The right. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
48. The left . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
49. Kinds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
50. Kind notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
51. Type constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
52. Kind of fun. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
53. Equational reasoning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
54. Shadow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
55. α-conversion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
56. Churn . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
57. Performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
58. Fleither . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
59. Flip. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
60. bimap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
61. Bifunctor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
62. Swap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
63. Bifunctorn’t . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
64. Quantification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
65. Tragedy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
66. Subversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
67. Positions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
68. Covariance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
69. Contravariance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
70. Constance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
71. Little boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
72. Profunctor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
73. Opa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
74. Profunity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
75. Mundane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222
76. Origami. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
77. Accumulate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
78. Pancake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240
79. Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
80. Reverse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
81. Concat. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246
82. Discovery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
83. Monoid . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
84. Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
85. Vocabulary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256
86. Concerns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262
87. Comfort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
88. maybe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271
89. either . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
90. Bool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
91. Conjunction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
92. Laziness . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283
93. Thunk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286
94. Weak head . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
95. Normal form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
96. Spine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
97. Lazy enough . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299
98. Equations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
99. Pattern much . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307
100. Types, please . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310
101. Closure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315
102. Num . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
103. Too eager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319
104. Eq . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
105. Lazy mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326
106. Naturals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328
107. Cavemen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332
108. Clingy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336
109. Troy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
110. Frogs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
111. Dialogue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346
112. Foldable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351
113. Politics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357
114. A hole new world . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358
115. Adventure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
116. Rebelión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365
117. Or something. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368
118. Disjunction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
119. Dot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375
120. Disjunctivitis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 376
121. Parsers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
122. Wild bool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 382
123. Surjection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386
124. Type synonyms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
125. Sequence. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
126. Split . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398
127. Guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
128. Æ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
129. Compost. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405
130. Leftovers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407
131. Two. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410
132. Wot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413
133. Twogether . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417
134. Tres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 419
135. To wrap up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
136. Cardinality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
137. Injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431
138. Invert. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433
139. Broken parts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434
140. Unit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
141. Plus one . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441
142. Times one. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
143. Equality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
144. Mon produit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
145. L’addition. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451
146. Less is more . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
147. Power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459
148. Ex falso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464
149. Myriad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
150. Spice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
151. Government. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472
152. Another one. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474
153. Alles klar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 477
154. Mechanical. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482
155. Poke. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 485
156. Beauté . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 486
157. So what? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
158. Fan. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
159. Choice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499
160. Why not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502
161. Não tem fim. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506
162. Location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
163. Relative . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 512
164. Absolute . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516
165. Attention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 521
166. Candy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 523
167. Small things . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526
168. Chow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 530
169. Bigger things . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 534
170. Digital . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537
171. Digitoll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
172. Open up . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 546
173. Digítame . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 554
174. Nearly . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 557
175. Other things. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
176. René . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561
177. Cease . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570
178. Soup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577
Copyright © Renzo Carbonara, 2019.

All rights reserved. Not for resale or redistribution.

This is an unfinished draft of the first few chapters of A Type of


Programming as of September 2019. The book is still in progress.
New chapters are published every few days. Find the latest version
at https://atypeofprogramming.com.

Send your comments to hola@atypeofprogramming.com.

Fonts used to render this text:

• EB Garamond © The EB Garamond Project Authors, 2017.


Licensed under the terms of SIL OFL Version 1.1.
https://github.com/octaviopardo/EBGaramond12
• Ioskeva © Belleve Invis, 2015.
Licensed under the terms of SIL OFL Version 1.1.
https://typeof.net/Iosevka
1. Computers
Computers blindly follow orders, and at some fundamental level,
programming is about giving computers orders to follow.
Ultimately, the expectation is that when a computer carries them
out, it will achieve a particular goal a programmer had in mind.
Coming up with these orders, however, is not easy. While
computers are thorough and efficient, they are also rather limited in
the vocabulary of instructions they can understand. They mostly
know how to do arithmetic and store data, which means our orders,
as complex as they may be, can only be conveyed in those terms.
Even deceptively simple programs can involve thousands or
millions of these instructions, each of which needs to be correct and
executed at the right time. And if we consider that computers
won’t judge whether any of these instructions are right or wrong,
some of which could have important consequences on our lives, it
should be easy to appreciate how taking appropriate measures to
prevent undesirable outcomes is the logical thing to do. In order to
accomplish this, however, we need a different perspective.

Surprisingly, these computer instructions are a bad tool for


reasoning about computer programs. Yet, it is only through
reasoning that we can be confident about the correctness of our
solutions, and more importantly, about the correctness of our
problems. At the other end of the programming spectrum, far away
from computers, we have our imagination. Programming is the
conversation that happens while these two ends struggle to
understand each other. We will explore this process and how to
improve it.

This book doesn’t assume any previous programming knowledge,


yet both newcomers and experienced programmers are welcome.
Those approaching software development for the first time will
discover a fascinating field while acquiring a good understanding of
the principles and tools involved, whereas the experienced shall
have their conceptions challenged by a different type of
programming. We will use the Haskell programming language as
our main vehicle, and while this book is not solely about Haskell
but about programming, it will be very thorough at that.

But please, be patient. We prioritize the kind of deep and holistic


understanding that stays with us for a very long time, the one that
teaches questions. This means the topics in this book are presented
in a rather unorthodox and entertaining fashion where immediate
practicality never seems to be a goal. Don’t worry, we will get there.
And when we do, we won’t need to look back.
2. Dare
We can’t really talk about programming without defining what a
program is, which we can’t do unless we understand exactly what it
is that we are trying to solve. For this, we first need to sample the
world for suitable problems to tackle, a seemingly intractable
endeavour unless we understand the limits and purpose of the field,
for which we most certainly need to be able to talk about it. This is
the very nature of new ideas, and why appreciating them is often so
hard. We need to break this loop somehow. We need to
acknowledge that there might be a problem to be tackled even if we
can’t readily recognize it at first, and see how the proposed idea tries
to approach it.

Breaking this loop, actually, is not a particularly hard thing to do in


our imagination. A little dare, that’s all we need. There, boundaries
and paradoxes are gone. We can fantasize allegedly impossible
things and dwell on problems they say can’t be solved. We can
build, we can explore every future. To indulge in thought that
challenges our understanding and that of others is not only
interesting, it is a requirement. A curious and challenging mind is
what it takes to make this journey.

But why would we do that? Why would we care? Well, look


around. What do you see? There is a computer in our phone, there
is another one in our car. There is one for talking to our families
and another one for knowing how much money we have. There are
computers that spy, there are computers that judge. There are
computers that help our business grow, and some, they chant, that
take our jobs away. We even have computers saying whether we
matter at all. Computers are our civilization, we have put them up
there quite prominently. We care about programming because it is
our voice, and only those who know how to speak stand a chance.
It’s our power, freedom and responsibility to decide where to go
next. We care because civilization is ours to build, ours to change,
ours to care for.
3. Machines
Let’s picture ourselves in a not so distant past looking at our
landline phone, looking at the elevator in our building, looking at
our clock. Besides their usefulness, these machines have in common
a single purpose. Not a shared single purpose unfortunately, but a
single different one each of them. The phone phones, the elevator
elevates, and that is all they will ever do. But these machines,
however disparate, at some fundamental level are essentially just
interacting with their environment. Somehow they get inputs from
it, and somehow they observably react according to pre-established
logical decisions. We press a key and a phone rings. Another key
and we are on a different floor. Yet, we rarely see these machines
and their complex and expensive electronic circuitry repurposed to
solve a different problem if necessary.

What happens is that the wires and electronics in these machines


are connected in such a way that their accomplishments are mostly
irrelevant to the wider electronic community. Like those
steampunk contraptions, they each represent a solution to a finite
understanding of one particular problem, and not more. But, is
sending electricity to the engine that lifts the elevator really that
different from sending it to the one that moves the hand of the
clock? No, it is not. The logical decisions however, of when to do
what and how, are. We say that the purpose of these machines is
hardwired into their very existence, and it cannot be altered
without physically modifying the machine itself. And yes, perhaps
it is possible to adjust the time in a clock, but subtle variations like
that one are considered and allowed upfront by the grand creators
of the machine, who left enough cranks, switches and wires inside
that we can alter this behaviour somehow within a known limited
set of possibilities.
But if interacting with the environment is the essence of these
machines, and moreover, if they are built with many of the same
electronic components: Isn’t there some underlying foundation
that would allow them to do more than what their upbringing
dictates? Luckily for us, and for the steampunk fantasies that can
now characterize themselves as nostalgic, there is. And this is what
computers, otherwise known as general purpose machines, are all
about.
4. Programs
What differentiates computers from other machines is that their
purpose, instead of being forever imprinted in their circuitry by the
manufacturer, is programmed into them afterwards using some
programming language such as that Haskell thing we mentioned
before. The general purpose machine is a canvas and a basic set of
instructions that we can combine in order to achieve a purpose of
our choosing while interacting with the outside environment
through peripherals such as keyboards, microphones or display
screens. A computer program, in other words, is something that
takes into account some inputs from the environment where it
runs, and after doing some calculations, provides some kind of
output in return. We can introduce some notation to represent this
idea.

program :: input -> output

Prose is an excellent medium for conveying ideas to other human


beings. However, prose can be ambiguous, it wastes words talking
about non-essential things, and it allows for the opportunity to
express a same idea in a myriad of different ways. These features,
while appealing to the literary explorer, just hinder the way of the
programmer. Computers won’t judge whether we ordered them to
do the right thing, so we can’t afford to have ambiguities in our
programs. We need to be precise lest we accomplish the wrong
things. Irrelevant stuff may entertain us as great small talk material,
but computers just don’t care, so we avoid that altogether. This is
why a precise notation like the one above becomes necessary.

Perhaps surprisingly, our notation, also known as syntax, is part of


a valid program written in the Haskell programming language, a
language that we use to program computers, to tell them what to
do. This is why among many other fascinating reasons we’ll come
to cherish, this book uses Haskell as its main vehicle. The distance
between our thoughts and our Haskell programs is just too small to
ignore. We can read program :: input → output out loud as “a
program from inputs into outputs”, and as far as Haskell is
concerned, it would be alright.

Computers themselves don’t understand this Haskell notation


directly, though. We use this notation for writing our programs
because it brings us clarity, but computers don’t care about any of
that. For this, we have compilers. Compilers are programs that take
as input the description of our program, called source code, here
specified using the Haskell programming language, and convert it
to an executable sequence of instructions that computers can
actually understand and obey. That is, we could say a compiler is
itself a program :: source code → executable, if we wanted to reuse
the same notation we used before.

Compiling is actually a complex, time-consuming and error prone


operation, so it’s usually done just once and the resulting executable
code is reused as many times as necessary. When we install a new
program in our computer, for example, chances are we are
installing its executable version, not its source code. Quite likely the
author already compiled the program for us, so that we can start
using our program right away rather than spend our time figuring
out how to compile it ourselves first. This is not different from
what happens when we buy a new car, say. The car has already been
assembled for us beforehand, and from then on we can drive it
whenever we want without having to re-assemble it.
5. Types
What are our input and output, though, concretely? We don’t yet
know exactly, but it turns out it doesn’t really matter for our very
first program, the simplest possible one. Can we imagine what such
program could possibly do? A program that, given some input, any
input, will produce some output in return? If we think carefully
about this for a minute, we will realize that there’s not much it
could do. If we were told that the input was an apple, the output of
the program could be apple slices or apple juice. If we knew that the
input was a number, then the output could be that number times
three. Or times five perhaps. But what if we were told nothing
about the input? What could we ever do with it? Essentially, we
wouldn’t be able do anything. We just wouldn’t know what type of
input we are dealing with, so the only sensible thing left for us to do
would be nothing. We give up and return the input to whomever
gave it to us. That is, our input becomes our output as well.

program :: input -> input

Our program, the simplest possible one, can now be described as


simply returning the input that is provided to it. But of course, we
can also look at this from the opposite perspective, and say that the
output of our program is also its input.

program :: output -> output

Celebrate if you can’t tell the difference between these two


descriptions of our program, because they are effectively the same.
When we said that our input becomes our output, we really meant it.
What is important to understand here is that whether we say input
or output doesn’t matter at all. What matters is that both of these
words appearing around the arrow symbol →, respectively
describing the type of input and the type of output, are the same. This
perfectly conveys the idea that anything we provide to this program
as input will be returned to us. We give it an orange, we get an
orange back. We give it a horse, we get a horse back. In fact, we can
push this to the extreme and stop using the words input or output
altogether, seeing how the notation we use already conveys the idea
that the thing to the left of the arrow symbol is the input type, and
the thing to its right the output type. That is, we know where the
input is, we know where the output is, we know they are the same
type of thing, and we don’t care about anything else. So, let’s just
name this x for mystery.

program :: x -> x

This seemingly useless program, actually, is one of the very few


important enough to deserve a name of its own. This program is
called identity, and it is a fundamental building block of both
programming and mathematics. It might be easier to appreciate this
name from a metaphysical point of view. Who is the horse? The
horse. Who am I? It is me. Indeed, philosophers rejoice, our
program addresses the existential question about the identity of
beings at last, even if in a tautological manner. In Haskell we call
this program id, short for identity.

id :: x -> x

Actually, we could have named the identity program anything else.


Nothing mandates the name id. As we saw before when we
arbitrarily named our mystery type x, names don’t really matter to
the computer. However, they do matter to us humans, so we
choose them according to their purpose.

There is one last thing we should know about naming. Usually, we


don’t really call programs like these programs, we call them
functions. The term program does exist, but generally we use it to
refer to functions complex enough that they can be seen as final
consumer products, or things that do something yet they don’t
exactly fit the shape of a function. Text editors, web browsers or
music players are examples of what we would often call a program.
In other words, we can say we just learned about id, the identity
function. Generally speaking, though, we use these terms more or
less interchangeably, as we have been doing so far.
6. Names
We also have useful programs. They are less interesting, much more
complicated, but deserve some attention too. We were able to
discover the identity function because we didn’t know much about
the types of things we were dealing with, and this ignorance gave us
the freedom to unboundedly reason about our problem and derive
truth and understanding from it. What would happen if we knew
something about our types, though? Let’s pick a relatively simple
and familiar problem to explore: The addition of natural numbers.

As a quick reminder, natural numbers are the zero and all the
integer numbers greater than it. For example, 12, 0 and 894298731
are all natural numbers, but 4.68, π or -58 are not.

We said that our identity function, when given something as input,


will return that same thing as output. This is supposed to be true
for all possible types of inputs and outputs, which of course
include the natural numbers. In Haskell, we can refer to this type of
numbers as Natural. That is, if for example we wanted to use the
identity function with a natural number like 3, then our id function
could take the following type:

id :: Natural -> Natural

That is, this function takes a Natural number as input, and returns a
Natural number as output. In other words, the type of this function
is Natural → Natural. Yes, just like numbers, functions have their
own types as well, and they are easy to recognize because of the →
that appears in them, with their input type appearing to the left of
this arrow, and their output type to its right.
Presumably, if we ask for the id of the Natural number 3, we will get
3 as our answer. Indeed, this would be the behaviour of the identity
function. However, we also said that names can be arbitrarily
chosen. Usually we choose them in alignment with their purpose,
but what if we didn’t? What would happen if we named our id
function for Natural numbers something else instead? Let’s try.

add_one :: Natural -> Natural

Interesting. At first glance, if we didn’t know that we are dealing


with our funnily named identity function, we would expect a
completely different behaviour from this function. The name
add_one and the type of this function suggest that given a Natural
number, we will add one to that number. That is, given 3 we would
get 4. Very interesting indeed.

And what if we were told that one of the following functions is our
identity function, renamed once again, and the other one adds as
many numbers as it states? Look carefully. Can we tell which is
which?

add_two :: Natural -> Natural

add_three :: Natural -> Natural

Despair. Sorrow. We can’t tell. We can’t tell without knowing the


answer beforehand. The more we know about the things we work
with, the less we know about the work itself. When we knew
nothing about x, we knew that all we could ever do was nothing.
That is, a function x → x, for all possible types x, could only ever
have one behaviour: Returning x unchanged. But now we know
about natural numbers. We know we can count them, add them,
multiply them and more, so learning that a function has a type
Natural → Natural is not particularly helpful anymore. A function of
this type could process the Natural number given as input in any
way it knows how, return the resulting Natural number as output,
and it would be technically correct, even if possibly a fraud.

Is this the end? Have we lost? I am afraid that in a sense we have.


This is part of the struggle we talked about. Suddenly we can’t
reason anymore, and are instead left at the mercy of optional
meaningful naming. If we name something add_one, then we better
mean add one, because we have no way to tell what’s what.
7. Expressions
Was it all a lie, then? How can it be that us programmers can’t tell
what a program does? Well, it’s complicated. First we should know
that in this book we haven’t really been programmers yet. We
haven’t even been computers, no. The role we’ve taken so far,
which should explain why we insisted so much in understanding
the types of our inputs and outputs, is that of the type-checker.

Computers care about instructions to follow, but not so much


about their meaning. They care about a function multiplying two
numbers together, but they couldn’t care less about said function’s
name, nor whether those numbers are naturals, fractions or phone
numbers. They don’t even care whether they are compatible things.
Have you ever tried multiplying a phone number by five? No?
What about shoes times some amount of cheese? Not particularly
smart things to do, are they? Yet, a computer will happily do them,
resulting of course in gibberish. We use types, checked by the type-
checker, to prevent these things from happening. In our example,
when we said the type of data we were dealing with was Natural
numbers, we made it impossible to use our function on other types
such as text or potatoes.

Types are relevant to both type-checkers and humans, but not to


computers. As computer programmers, surprise, we also need to
write the part of our program that is relevant to computers. That is,
we need to write the expressions that ultimately become the
instructions that our computer can perform. When we program,
essentially, we always deal with two different realms: That of types,
where we can reason about things and prevent nonsense, and that
of expressions, where we react to unknown inputs from the
environment and tell the computer what to do in return. Let’s see
an example of how we can deal with this in our add one function,
this time including both the type and the expression that fully
define it.

add_one :: Natural -> Natural


add_one = \x -> x + 1

As before, add_one is a function that takes a Natural number as


input, and after doing some calculations, it returns another Natural
number. This hasn’t changed. Of course we can’t know which
number we will get, but at least we know it will always be a natural
number, not a fraction or something else. That is, our add_one is still
a function whose type is Natural → Natural. We can see this in the
first line of our program.

On the second line we have some new notation. The first thing to
notice is that we are mentioning the name add_one again, but this
time followed by =. Whereas :: allowed us to specify a type for this
name, = is saying that the name add_one is equal to the expression that
appears to its right. If we were so inclined, we could read this out
loud as “the name add_one, whose type is Natural → Natural, is equal
to the expression \x → x + 1”.

Finally, we have the expression itself. Expressions defining the


behaviour of a function start with a backslash symbol \ and extend
all the way to the right. They are called lambda expressions. Like in
the function type, we see the arrow symbol again, and we still have
inputs to its left and outputs to its right. The right hand side should
be quite straightforward if we remember anything from high
school: We are just adding 1 to some mystery number called x. So, if
x happens to be 3, then x + 1 will result in 4, which would be the
Natural output of this function. But of course, 3 is just an example
here. To the left of the arrow symbol we deal with the input of this
function, which according to its type could be any Natural number,
not just 3. From our perspective, we have no way of knowing which
number this will be, we only know that it will be some Natural. The
x here is the name we’ll use to refer to this number on the right side
of the arrow symbol, as we did when we wrote x + 1. We could
have used any name here, it doesn’t matter which. We chose x
because we like mystery, that’s all. We can read \x → x + 1 out loud
as “the function whose input we name x, and whose output is x +
1”.

With this new knowledge, we can finally give the unsurprising full
implementation of our beloved identity function, including both
its type and the expression that defines its behaviour.

id :: x -> x
id = \x -> x

We named both the mystery type and the mystery value x because it
makes the whole thing look terribly handsome. But, of course, we
could have named these things anything else. It’s all the same to
Haskell, names are just for us humans.

truck :: helicopter -> helicopter


truck = \motorcycle -> motorcycle
8. Runtime
A fundamental difference between types and expressions is the time
when they exist. Type-checking is performed as part of the
compilation process of our program, so if type-checking fails,
compilation will fail as well and we won’t be able to get our hands
on an executable version of our program. This is beautiful, because
we likely prevented a malfunctioning program from existing at all.
However, we need to keep in mind that compilation happens just
once for the programs that we build, and usually before our
programs even leave “the factory”. So, we are limited by our
understanding of the environment at that time. Imagine, for
example, that the program we are trying to build is a calculator. We
know beforehand what the available digits and function keys in the
calculator will be, as well as their behaviour. However, we can’t
possibly know beforehand in which order these keys will be
pressed, as that really depends on what calculations the person
using the calculator is trying to solve. We need to write that part of
our program, the one that deals with the unknown, somewhere.

The realm of expressions exists whenever our program is executed,


a time we formally call the runtime of our program. There we deal
with things that are not known at compilation time, and in those
expressions we find the real value of our program. Think about it:
If all the answers and possible input values were known at
compilation time, then it wouldn’t be necessary to execute the
program at all. If the programmers that created the calculator knew
that all we ever wanted to do was multiply five times seven, they
would have just whispered thirty-five to us rather than go and write
a program. Of course our programs will showcase their utility when
they are executed and not before, time and time again. Which,
ironically, is why we care about types that only exist at compilation
time so much; they help us get our expressions right so that they
don’t fail time and time again at runtime.

So when we said before that we couldn’t tell the difference between


add_two and add_three, what we meant is that unless we get to see
inside the expressions that define the behaviour of these functions,
which many times we can’t or don’t want to do, we need to trust
the names and documentation for these functions to speak the
truth. Naming, thus, becomes one of the most critical issues in
software development.
9. Function application
More or less we have some idea now of what functions are and do.
What do we do now? Why, we use them, of course.

First we need to know the type of the function we want to use. As


an example, let’s try with our add_one function of type Natural →
Natural. This type is saying that if we want to use this function,
then we need to provide a Natural as input, so first we need to
obtain a Natural somehow.

It turns out creating a Natural number is quite straightforward: We


just write the literal digits of the natural number we want and
that’s all. For example, 3, 17 or 0 are all values of type Natural.
Actually, we can refer to them as expressions of type Natural as well.
Yes, so far we have only talked about expressions that describe
functions, but actually, anything that can exist at runtime is an
expression of some type. Alternatively, we could refer to them as
terms. Right, right, the words value, expression and term can be
used interchangeably. Why do we have so many names for the same
thing? Who knows! Probably some historical accident.

Now, on the one hand we have a function of type Natural →


Natural, and on the other hand we have a Natural number. How do
we feed this number to the function? Well, not by clapping those
hands, no. Wouldn’t that be fun, though? No, the way we do it is
by simply juxtaposing the function and its input. That is, by
putting them next to each other. So, if we want to add_one to the
number 3, we just say add_one 3. Almost as nice as clapping, isn’t it?
The function always goes on the left side of this juxtaposition, and
its input to its right. And of course, as usual, we have a myriad of
words to describe what just happened. We could say that we used
add_one on 3, that we called add_one with 3, or that we applied
add_one to 3. These, again, are all more or less interchangeable
words, but we do prefer to talk about applying functions for
reasons that will become apparent later on.
10. Perspective
So what can we say about add_one 3? Well, arguably the most
obvious thing about it is that it represents the idea of the number
four. So much so, actually, that we could name this expression four.

four = add_one 3

But if we asked this same question to the type-checker, it would say


something else. It would say that the most obvious thing about
add_one 3 is the fact that this results in an expression of type Natural.

four :: Natural

This “disagreement” is quite fine, actually. Remember that types


and expressions have different concerns, so it is only natural that
they’ll come to appreciate different facts about programs. These
two statements about four are in harmony. They don’t contradict
each other, they just state different facts about a same truth.
11. β-reduction
Can we use our four anywhere we could have used the literal
number 4? Well, we can’t write things such as 123four5, since
Haskell would try to interpret that as the literal digits that make up
some number, and of course it will fail at that. But sure, we can use
four anywhere a value of type Natural is expected. We could even
say five = add_one four. Let’s prove ourselves the meaning of four
by doing some of the work Haskell diligently does when applying a
function.

We said before that the equals sign = we use when binding


expressions to names could be read out loud as “the name on the
left is equal to the expression on the right”, and we really meant
that. Particularly, this means that if we are mentioning some name
as part of an expression, we can replace that name by the expression
that defines it and the result should be the same. So if we start with
four = add_one 3 and replace add_one by its definition, we get four =
(\x → x + 1) 3. This is a valid Haskell function application: We are
simply juxtaposing a function (\x → x + 1) to its input 3. It looks
awkward this time, sure, but still correct. Those extra parentheses
are there to ensure that we don’t include that trailing 3 in our
function definition, otherwise the meaning of this whole
expression would be different, just like how (1 + 2) * 3 doesn’t
mean the same as 1 + 2 * 3, if you remember anything from
elementary school.

We also know that the function definiton syntax binds its input to
some name. That is, when we say (\x → x + 1), any input we
provide to this function will be bound to the name x within these
parentheses. And names, we said, can be replaced by the expression
they represent, which in our example will be the number 3. That is,
we could write four = (\3 → 3 + 1) 3. Wait, what? Is this correct? It
looks quite weird, but actually, this happens to be accidentally
correct Haskell. Not exactly what we are looking for, though.

It is important to remember that what justifies the existence of a


function is the unknown. If we already knew what some input
would be, then we wouldn’t need this ritual of using a name to
refer to a thing, rather than mentioning the thing itself. That is, had
we known x was 3, we could have said 3 + 1 rather than x + 1. We
know this now, though, so we can simply remove the function
definition and its application, which were there only to give some
meaning to the now gone name x. That is, we can simply say four =
3 + 1, which of course is the same as saying four = 4, which proves
that our definition of four was correct all along. Isn’t that nice?

Beta reduction, stylized β-reduction, is the name we give to this


process of replacing a function application like (\x → x + 1) 3 with
3 + 1, where 3, the input to \x → x + 1, which is bound to the name
x, replaces the occurrences of x in that lambda expression to finally
become 3 + 1. And since the x that the function was expecting as
input has already been provided by the function application, we
can also remove it from the left side of the arrow symbol → in the
lambda expression. That is, beta-reducing (\x → x + 1) 3 results in 3
+ 1, not in \x → 3 + 1.
12. Parameters
Our add_one function is a bit restrictive in that it only allows us to
add one to a Natural number. Nevertheless, being able to add one is
in theory sufficient machinery for us to add bigger numbers. We
can, for example, add three to some number by “simply” applying
add_one three times.

add_three :: Natural -> Natural


add_three = \x -> add_one (add_one (add_one x))

Indeed, this approach works and is conceptually quite simple. As


soon as we know how to add one, we also know how to add every
other natural number by repeatedly doing the same, without
having to learn nor do anything new. However, hopefully we can
see how doing this for larger numbers gets a bit ridiculous. Imagine
implementing add_one_million this way. Crazy.

Simplicity is quite a tricky topic in programming. What may be


simple from a conceptual point of view, where we pay attention to
the meaning and essence of things, might not be simple from
economic or ergonomic perspectives, and vice-versa. This is yet
another battle in the struggle between computers and thoughts.

What we would like to do instead of repeatedly applying add_one, is


to have a more convenient function for adding arbitrarily chosen
natural numbers. That is, rather than have an add_one function
taking a Natural as input and adding one to it, we would like an add
function that takes two Naturals as input and adds them together.
seven :: Natural
seven = add 2 5

Here we are applying a function named add to two inputs by


juxtaposing them separated by some whitespace, and then assigning
the result to the name seven. Presumably, this add function is one
that adds Natural numbers together. Hopefully none of this is too
surprising, seeing how it’s not that different to what we’ve been
doing so far when applying functions that take just one input. In
Haskell, our functions can take as many inputs as we want. Let’s see
how add itself is defined.

add :: Natural -> Natural -> Natural


add = \x y -> x + y

This is not particularly different from before either, but let’s


analyze it step by step. The first thing to notice is how the type of
this function has changed. Whereas in add_one we had Natural →
Natural meaning a function that takes a Natural as input and returns
a Natural as output, here we have Natural → Natural → Natural, more
or less meaning a function that takes two Naturals as input, and
returns a Natural as output, where the rightmost Natural in this
function type is the output type, and everything to the left of the
rightmost arrow symbol → are the function inputs, each one
separated by yet another arrow symbol →. Actually, to be more
precise, we say that each of these Naturals given as input is a
parameter or argument to this function. When considered
together, these parameters constitute the entire input to the
function. In other words, in a function type, to the right of the
rightmost arrow symbol → we have the output type, and to its left
we have its input, made out of one or more function parameters.
On the following line we have the actual expression that defines
what our function actually does. Remember, it’s called “add”, it has
type Natural → Natural → Natural, but the type-checker can’t really
tell what this function does. We as programmers need to look inside
of it, or trust its author to have given it a reasonable name. For all
the type-checker knows, it could be a fraud. Luckily, this time there
are no surprises in this area. To the right of the arrow symbol → we
can indeed see that two things are being added together using the +
operator. Which two things? Well, x and y, the names we chose
when binding each of the parameters of our function to the left of
the arrow symbol →, corresponding to the Naturals taken in by this
function and distinguished from each other by whitespace.

Generally speaking, a function with type A0 → A1 → … → B, can be


defined using a function expresion like \a0 a1 … → b, where the
names written in lowercase conveniently correspond to the types
written in uppercase in this example, and as many parameters as
necessary can replace those dots … written here as placeholders.
13. Datatypes
Where do types come from, anyway? Some, like Natural, come with
Haskell already, but they aren’t particularly special. We could have
created Natural ourselves if it hadn’t been there already. Actually,
let’s do that, let’s recreate some of the types that come with Haskell.

One of the things we will want to do very early in our programming


is enumerate related things and tell them apart. For example, we
may want to tell apart the seasons of the year so that our
hypothetical travel agency can suggest travel destinations in the
right season. Otherwise, we might end up offering our customers a
trip to a cold beach in winter, a package unlikely to sell much. To
keep things simple, let’s assume there are only four seasons in the
year, even if in some geographies it doesn’t feel that way. Winter,
spring, summer or autumn. In Haskell, it is quite easy to enumerate
these four seasons.

data Season = Winter | Spring | Summer | Autumn

We have some new syntax. To the left of the equals = sign, we are
saying that Season is the name of the new type of data, or datatype,
we are introducing. That is, Season is now a type that we could
mention in places like those where we mentioned Natural so far.
The word data is just part of the syntax that Haskell uses for
defining new data types, we can mostly ignore it. Types, such as
Natural or Season, always start with uppercase letters.

To the right of the equals sign we see our seasons enumerated,


separated by vertical bars |. This is saying a value of type Season can
only ever be one of Winter, Spring, Summer or Autumn. These four are
called the constructors of the Season type, as it’s only by using one of
them that we can construct a value of type Season. This has the
important implication that we as programmers know that a value
of type Season must be just one among these four constructors. Not
zero, not two, not more. One, always one. We call types such as
Season, used to represent one among many, sum types, for reasons
that will become apparent later on. The order in which we list these
constructors is not important, what matters is that they are
different and start with an uppercase letter.

Actually, what we are seeing here is not that different from what
we’ve seen so far regarding Natural numbers, if we consider that in
order to construct a value of type Natural out of thin air, we need to
write one number like 0 or 27 literally. That is, a value of type
Natural is just one natural number among infinitely many of them.
The definition for a type like Natural is a bit more complicated, but
conceptually is not that different from other sum types such as
Season. It is a beautiful thing how in programming, when we stay
close to reason, we invest our time studying small examples, and
once we are confident in our understanding of the principles
involved we can scale up our knowledge to larger problems without
any friction. It really is beautiful.

So, now we can construct values that precisely represent our seasons
by simply using one the four constructors for Season.

my_favorite_season :: Season
my_favorite_season = Autumn

Of course, trying to assign the type Season to something different


than the constructors we just enumerated will fail. For example
saying that 9 is of type Season will cause the type-checking of our
program to fail. And similarly, trying to say that Winter or any of the
other constructors is a value of a type different from Season will also
fail. This is quite desirable, considering the whole reason why we
have types at all is to prevent us from doing silly mistakes such as
trying to interpret a season of the year as a number.

When analyzing the source code we write, it is quite important to


consider the perspective of the type-checker as well. While we as the
authors of this code can see both the type and the constructor being
used, the wise type-checker only sees the type. It doesn’t know
which our favorite season is, it just knows that it must be one of the
four we have enumerated.
14. Pattern matching
Let’s try and do something useful with our Season sum type. For
example, let’s write a function that given a Season as input returns
the opposite Season as seen from the other hemisphere. For
example, when it’s Winter in the northen hemisphere, it’s Summer in
the southern one. Or when it’s Autumn in Australia, it’s Spring in
Italy. We get the idea.

opposite_season :: Season -> Season


opposite_season = \x ->
case x of
{ Winter -> Summer
; Spring -> Autumn
; Summer -> Winter
; Autumn -> Spring
}

We have some new syntax. As before, we are using a lambda


expression to define our opposite_season function, binding our input
parameter of type Season to the name x. However, this time our x
could be any of the four constructors we have enumerated in our
Season datatype, and depending on which one it is, we want to make
a different decision about what to return. We need something
more.

Notice that this time we are writing the function definition in


multiple lines. This is alright. We will learn more about Haskell’s
indentation rules as we go along, but in general they shouldn’t be
that surprising. Here the body of the lambda expression is not
exactly to the right of the arrow symbol as before. Rather, it is below
and indented to the right compared to the beginning of the
previous line, which accomplishes the same as putting it to the right
of the arrow symbol. Anyway, not important.

If we consider this x from the perspective of our type-checker, we


can’t tell which Season we are dealing with. Remember, the
compiler only has an understanding of the environment as it was
when it first compiled our program, so it can’t possibly know to
what Season we will be applying our opposite_season function.
Imagine, for example, that we are trying to apply opposite_season to
the current calendar season at the time we run our program, a value
that will definitely change depending on when we do so. We need
to analyze this x at runtime, rather than compile-time, to determine
its value. For this, we use a case expression.

Our case expression starts where we say case x of and extends all the
way to the end of our function. Let’s pay attention to the left side
of the arrows on the following lines. Just like we listed all the
possible constructors when we defined our Season datatype, here we
enumerate again all the possible constructors that could have been
used to obtain x, the Season value we are scrutinizing. Our x will
definitely be one among these four constructors, since they
represent all the possible ways of constructing values of type Season.
So, when one of these constructors matches the actual value of x,
then the expression that shows up to the right side of its arrow
symbol → will be returned. There, to the right, we are just
constructing new Season values as we have done before, making sure
we map every Season to the one in the opposite hemisphere.

If we look at this from a visual perspective, to the left of our arrow


symbols we are listing all of our constructors as some kind of
patterns or stencils we want to compare against x, hoping that one
matches so that we can proceed to return what’s to the right of its
arrow. In fact, formally, this process of enumerating all the possible
ways to construct a datatype but for the purpose of scrutinizing it
through a case expression is called pattern matching. It can become
more sophisticated than just an enumeration of the constructors,
but we’ll discover more about this later on.

Formally, a case expression has the shape case s of { p0 → e0; p1 →


e1; … }, where s is the original expression we want to scrutinize and
pattern match against. Each of p0, p1, … are the patterns we want to
try and match against s, and each of e0, e1, … are the corresponding
expressions we will return as result in case the pattern to the left of
their arrow symbol → matched. These e0, e1, … expressions, of
course, are all of the same type, since they are all the possible values
that this entire case expression can take, and expressions always have
just one type. In our case, their type is Season. This type matches
that of s, but that’s just a coincidence and we’ll soon see examples
where this doesn’t happen.

And actually, not only are those surrounding brackets {} and


semicolons ; ugly, but also they are unnecessary. Instead, we can
just write each pattern on a different line like we did in our lambda
expression, and provided they are properly aligned with each other,
it would be the same as if we had used the brackets and semicolons.
That is, the following definition of opposite_season means exactly
the same as the one before.
opposite_season :: Season -> Season
opposite_season = \x ->
case x of
Winter -> Summer
Spring -> Autumn
Summer -> Winter
Autumn -> Spring
15. Exhaustiveness
A lovely thing about pattern matching in case expressions is that
the compiler will yell at us if we don’t explicitly list all the patterns
that could potentially match the value we are scrutinizing. For
example, had we written something like the following, the type-
checker would have told us that we forgot to deal with the
beautiful Autumn and refuse to compile our program.

case x of
Winter -> …
Spring -> …
Summer -> …

This behaviour is quite reasonable and desirable. Of course we


want our program to be able to deal with all reasonable inputs.
Otherwise, for example, it may crash if we run it in Autumn. We want
the compiler to reject a program like this.

Sum types and this accompanying exhaustiveness check done by the


compiler, ensuring that we always deal with every possible input
scenario in our program, are some of the most beautiful, simple,
and powerful tools we will encounter in our programming journey.
It can’t be overstated how crucial sum types are if we want to build
reliable and clear software. If you only take one thing out of this
book, take sum types.
16. Strings
You might be surprised to learn that Haskell, somehow, is one of
the very few languages out there that actually supports this very
basic concept of a sum type. Most other languages fail to
comprehend the importance of this situation and simply don’t
allow programmers to express the idea of either this or that at all, let
alone do any exhaustiveness checking or pattern matching. Come
on, let’s hold hands and carefully explore this pain together to
understand why this is so important.

The fact that our opposite_season function takes a Season as input


and returns yet another Season as output is just an example. We
could, of course, return values of a different type as well. Let’s do
that, let’s write a function that more or less tells us the temperature
in each season.

season_to_temperature :: Season -> String


season_to_temperature = \x ->
case x of
Winter -> "cold"
Spring -> "warm"
Summer -> "hot"
Autumn -> "chilly"

We are mentioning yet another type for the first time here, String,
which already comes with Haskell. A String value is essentially text,
and is usually written between double quotes "like this". So, just
like how writing the digits of a number as 123 allows us to create a
numeric value of type Natural out of thin air, writing some
characters between double quotes " allows us to construct a new
textual value of type String. The word “string” refers to the fact
that a textual value is, metaphorically, a string of individual
characters one after the other. Our season_to_temperature function
is just returning a textual representation of the expected
temperature for a given Season.

Can we go in the opposite direction, though? Let’s try.

temperature_to_season :: String -> Season


temperature_to_season = \x ->
case x of
"cold" -> Winter
"warm" -> Spring
"hot" -> Summer
"chilly" -> Autumn

In principle it seems fine, but this new function is actually wrong.


In fact, if we try to compile it, Haskell will reject it saying that the
patterns in our case expression are not exhaustive. Why? Well, if we
look at the type of this function, it says that given a String, any
String, it will return a Season. However, that’s not what the actual
implementation of this function does. Sure, it gives the correct
result when given one of these four known strings, but what
happens when a different unknown string is provided? Pain. This
function doesn’t know what to do if somebody provides
"hamburger" as input. The program would just crash in that case.
That’s what programming in languages without sum types feels like,
they shift the burden away from the types and put it in the
expressions, in the fallible human, relying instead on hope, prayer,
and a careful observation of the entire execution flow of our
program lest temperature_to_season is ever called with an undesirable
input.
How do we solve this? Well, the ideal solution, if we were starting
from scratch, would be to just not use String at all and instead
introduce a Temperature sum type listing all known posibilities, to be
used as the input of our temperature_to_season function, replacing
the current fluffy String.

data Temperature
= Cold
| Warm
| Hot
| Chilly

This time we are defining our datatype across multiple lines just to
showcase that it can be done. Had we written everything in the
same line as before, the result would have been the same. Not
important at all. With this new Temperature datatype, we can rewrite
our temperature_to_season function.

temperature_to_season :: Temperature -> Season


temperature_to_season = \x ->
case x of
Cold -> Winter
Warm -> Spring
Hot -> Summer
Chilly -> Autumn

Now this function definitely can’t fail. We are back in a happy


place.
17. Parsing
Still, Strings are ubiquitous, and we need to know how to process
them in their wild form in order to distill them into more precise
types such as Temperature or Season. Imagine, for example, that we
are implementing some kind of web form where we ask our users to
write their favorite temperature as text. Some may write "hot", some
may write "cold", and some may write something completely
unexpected such as "nice". Then, based on this user input, we
would like to suggest to them their likely favorite season for taking
some holidays.

As far as artificial intelligence goes, our program will be rather


dumb. Sorry. Yet, it will perfectly exemplify the most common
scenario we have to worry about when dealing with Strings. That is,
converting them into richer and more precise types. In concrete
terms, we will be converting Strings such as "hot" and "cold" into
proper values such as Hot and Cold, while safely discarding all other
Strings we don’t know about. Let’s start from a broken
implementation.

string_to_temperature :: String -> Temperature


string_to_temperature = \x ->
case x of
"cold" -> Cold
"warm" -> Warm
"hot" -> Hot
"chilly" -> Chilly

The Haskell compiler will tell us that this function is broken


because it fails to account for the infinite amount of text that can
be represented as different String values. For example,
string_to_temperature "swell" will cause our program to crash. How
do we solve this if it’s impossible to always convert a String to a
Temperature sensibly? Is "pizza" Hot or what? No, what we need to
do is to formally acknowledge that only maybe we will be able
convert a given String to a Temperature. Maybe, depending on
whether the given String is known or not.

We have learned that it is through types that we can reason about


our programs, so we want to put as much knowledge as possible
about our problem there, in the types. In our case, even if we don’t
know exactly to which String the caller will apply this function, we
know that it could potentially fail to convert the given String to a
Temperature. That is a fact that we want to share with our type
system, so the type of our string_to_temperature must change to
accommodate this.

string_to_temperature :: String -> Maybe Temperature

Maybe. Dare we guess what Maybe is all about? We haven’t really seen
this syntax before, where we have two words next to each other
show up in a type. We’ll talk about that later. What we can say,
however, is that Maybe Temperature must be some kind of sum type,
considering what we just said about the behaviour of this function,
which returns either a value of type Temperature whenever that’s
possible, or it safely reports that it was imposible to do so. Either
this or that. Yes, Maybe Temperature must be a sum type somehow.
Let’s see its definition.

data Maybe a = Nothing | Just a

We know some of this syntax. Here we are introducing a new


datatype, a sum type apparently called Maybe a that has two possible
constructors: Nothing and Just a. That’s more or less correct, but
actually, that a is neither part of the type name, nor of the
constructor. Just like we saw back when we talked about the
identity function and its mystery x that could take any shape, this a
is also a mystery type that functions as a placeholder for a concrete
type like Temperature. In our string_to_temperature example, every
standalone a that shows up in this definition is being replaced by
Temperature, but it could as well have been replaced by Chocolate,
Natural or something else in a different situation.

Let’s look at the value constructors first. Nothing is quite simple; it


stands alone just like Summer or Hot which we saw before. That is,
Nothing is a perfectly acceptable value of type Maybe a, or rather Maybe
Temperature in our case. Just on the other hand is a bit more
sophisticated. Seeing how this constructor is used in practice will
help us understand. Let’s just look at the full implementation of a
correct string_to_temperature to appreciate both Nothing and Just in
action.

string_to_temperature :: String -> Maybe Temperature


string_to_temperature = \x ->
case x of
"cold" -> Just Cold
"warm" -> Just Warm
"hot" -> Just Hot
"chilly" -> Just Chilly
_ -> Nothing

What’s happening in string_to_temperature is that, as promised, the


four known Strings "cold", "warm", "hot" and "chilly" are leading to
Just some result, whereas any other String, here represented by the
“wildcard” underscore symbol _, will result in Nothing. What’s
interesting to notice here is that we are using the Just constructor as
if it were a function, applying it to the value of type Temperature we
actually care to return. However, contrary to functions such as our
previous add_one, constructors don’t modify their input in any way.
Instead, they just wrap it unmodified and give them a new type.
Constructors are, essentially, little boxes where we can potentially
put other values. Some constructors, like Just, have room to keep
values inside them. Others, like Nothing, don’t. We can tell whether
this is the case by simply checking if there are any fields in the
constructor, just like that a in the case of Just.

It’s important to keep in mind that Just itself is not a value of type
Maybe a. Instead, it needs to be applied to some value of type a in
order to construct a value of type Maybe a. So, if Just can be applied
like any other function, then it must have a function-like type,
right? Indeed, it must. Constructors have types, and the type of
Just is a → Maybe a. In our example, this mystery placeholder a has
been replaced by Temperature everywhere, so in concrete terms our
particular Just will temporarily take the type Temperature → Maybe
Temperature when used. Again, this is similar to how when defining
our identity function we said id :: x → x, yet later we decided to
use id with a Natural number and id temporarily took the type
Natural → Natural where it was used. This substitution of a is not
something that we need to do explicitly in writing, however. It just
happens. We’ll see more about this phenomenon later.

Actually, Maybe on its own is not a type as we would expect it to be.


There are no expressions of type Maybe, but rather, expressions like
Nothing or Just Summer are of type Maybe Season, Maybe Temperature, or
more generally, Maybe x for some mystery type x. That is, Maybe never
stands alone, but instead, as if it were a function or a value
constructor, we always apply it to some other type. We know how
this works because we’ve seen it in the Just constructor which, also,
never stands alone, but rather we always apply it to some expression
of some type x when trying to get a value of type Maybe x. There are
no expressions of type Maybe because Maybe is not a type but a type
constructor. As the name suggests, a type constructor constructs a
type once it’s applied to some other type, much like how Just, a
value constructor, constructs a value when we apply it to some other
value. From values to values, from types to types. Don’t worry if
this sounds somewhat confusing now, we’ll come back later.

Anyway, if string_to_temperature gets a known String, then we


return the appropiate Temperature wrapped in the Just constructor.
Otherwise, we simply return Nothing rather than allowing our
program to crash. Both of these constructors return a value of type
Maybe Temperature, so the requirement that all patterns in a case
expression return a value of the same type is respected. In a few
lines of code we have safely dealt with the infinitely many Strings
that our function could be applied to.

This process of converting Strings to a more precise type is called


parsing. We can say that our string_to_temperature is a parser that
parses Strings into Temperatures. More generally, a parser is a
function that tries to convert a value of a less precise type to a value
of a more precise type. However, not every function that takes a
String as input is a parser. For example, the function that takes a
String as input and returns how many times the letter x appears in it
is not parsing anything, it is just describing a property about its
input.
18. Either
Our Season datatype hardcoded the four possible seasons when it
was defined. This makes sense, considering seasons are unlikely to
change any time soon. Well, not nominally at least. On the other
hand, in the case of a type like Maybe a, intended to convey the idea
of some value of type a maybe being there, it makes sense to leave
this a be just a placeholder so that we can reuse the very same
Nothing and Just constructors in different scenarios. Maybe
Temperature, Maybe Natural, Maybe Airplane, they all make sense. Being
able to reuse things is quite useful, so we appreciate Maybe leaving
that mystery a unspecified for us to choose in different scenarios.
However, while Maybe's reusability is quite handy, it still mandates
that one of its two constructors carry no payload at all. This makes
it impossible for us to use it to represent something more
meaningful than just some a, through Just, or the absence of that a
through Nothing. Imagine, for example, that we wanted to represent
the idea of “either this Natural or that other Natural”. How do we do
that? It is not possible with Maybe.

In Haskell, and much in the same reusability spirit as Maybe, out of


the box we get a sum type called Either that can be used to express
either this or that where both this and that can contain some useful
payload, rather than just one of them.

data Either x y = Left x | Right y

The names of the constructors Left and Right are not particularly
important. As we said before, Haskell doesn’t really care about
names, all it cares about is that we are consistent when we use them.
Presumably, the words “left” and “right” have something to do
with the fact that the x that is the payload of the Left constructor is
the leftmost parameter to the Either type constructor, whereas the y
that is the payload of the Right constructor is the rightmost one. Or
maybe it means something else. We don’t care.

The interesting thing to notice about Either is that not only both its
constructors carry a payload, but said payloads can potentially be of
different types: One mentions x and the other mentions y. For
example, we could have x be Temperature and y be Season, leading to
the type Either Temperature Season conveying the idea that we have
either a value of type Temperature or a value of type Season. In this
case, we would use the Left constructor if interested in the
Temperature value, or the Right constructor otherwise.

It is important to understand that values of type x or values of type


y are not themselves values of type Either x y. We must literally
write the words Left or Right to construct a value of type Either x y.
If a function is expecting an Either x y as input, but we apply it to
an y, then the type-checker will reject it. We must wrap that y in the
Right constructor for the type-checker to accept it. Similarly,
providing an Either x y where, say, an x is expected, will fail.

Let’s see an example of Either in a silly function that takes a value of


type Either Temperature Season as input and returns a word that
rhymes with the contained value. It really is silly.
rhyme :: Either Temperature Season -> String
rhyme = \x ->
case x of
Left Cold -> "old"
Left Warm -> "storm"
Left Hot -> "pot"
Left Chilly -> "lily"
Right Winter -> "sphincter"
Right Spring -> "bring"
Right Summer -> "bummer"
Right Autumn -> "ball"

We don’t care much for rhymes, and it shows. We care about safe
programs, though, that’s why we pattern matched against all eight
possible ways of constructing a value of type Either Temperature
Season. We hadn’t seen patterns that mention more than one word
yet, but there shouldn’t be any surprises there. For example, Right
Autumn is exactly the same we would write if we were trying to
construct a value of type Either Temperature Season, we know that.

We could also have known, without enumerating them, that eight


was the number of patterns or possible values in our Either
Temperature Season sum type. How? Well, it says so on the tin. The
name sum type comes from the fact that the number of possible
values a sum type has equals the sum of the number of possible
values all the other types mentioned in it have. Kind of. So, if
according to our definitions there are 4 possible ways to construct
Season and 4 possible ways to construct Temperatures, then there are
4 + 4 possible ways to construct a value of type Either Temperature
Season. That is, eight, which is exactly the number of patterns we
listed above. Technically speaking, we say that the cardinality of
Either Temperature Season is eight. We’ll give a proper definition of
this later on.
19. Isomorphisms
So, how is Either Temperature Season different from the following
handcrafted sum type?

data ThisOrThat = This Temperature | That Season

Well, they are different types, so if the type-checker is expecting to


see a value of type Either Temperature Season but gets a ThisOrThat
instead, it will complain. An obvious change is that while in Either
x y we are leaving room for those x and y to become anything, in
our awkwardly named ThisOrThat we are dropping those type
parameters and forcing the payload types to always be either a
Temperature or a Season.

Right Summer is not exactly equal to That Summer. Semantically,


though, we might argue they are, since the same information is
there in both representations, even if shaped a bit different. So are
they equal? Are they not? Fascinating phenomena such as these
seldom go unnoticed by mathematicians in their role as observers of
the beauty of the universe concerned about the essence of things.
Thus, they have given this a name. They have told us that while not
equal, these two things are isomorphic, more or less meaning that it
is possible to convert back and forth between them without any
loss of information.

They want proof, though. Mathematicians want proof that these


two representations are indeed isomorphic before we are allowed to
refer to them that way. So, since we are on our way towards
reaching that mathematical enlightenment ourselves anyway, we’ll
give them proof.
How do we do that? What is a proof anyway? Well, a proof is a
demonstration that a particular statement is always objectively and
unquestionably true. In our case, the statement we want to prove is
that our two values of types Either Temperature Season and
ThisOrThat, respectively, are isomorphic to each other. Which, as we
said, in practical terms means that we are able to convert back and
forth between these two representations without any loss of
information. Let’s start by writing two functions with types Either
Temperature Season → ThisOrThat and ThisOrThat → Either
Temperature Season which should allow us to convert between these
representations.

fromEither :: Either Temperature Season -> ThisOrThat


fromEither = \x ->
case x of
Left t -> This t
Right s -> That s

We named our function fromEither to highlight the fact that this is a


conversion from the Either datatype into something else. Similarly,
we can introduce toEither going in the opposite direction.

toEither :: ThisOrThat -> Either Temperature Season


toEither = \x ->
case x of
This t -> Left t
That s -> Right s

Hopefully what’s happening here is not too surprising: These


functions are the inverse of each other, they each undo what the
other does, if you will. We have some new syntax in the patterns of
our case expression as well. Rather than enumerating all possible
constructors, we are seeing things such as Left t in our patterns,
with a lower case t there rather than a specific value constructor.
This means that this pattern will match any value that uses the Left
constructor, and then simply bind whatever its payload is to the
name t. That is, in our example, that t will be the name for a value
of type Temperature. If we wanted to know exactly which value, then
we would need to further perform another case analysis on that t,
just like our previous rhyme function did. In this case, however, we
don’t really need to do that because all we want to do is put
whatever Temperature we received, unmodified, in a different
constructor. The same is happening in all the other patterns in this
example.

Many proofs in Haskell consist of just writing a program that


satisfies a particular type. For example, the proof that a value of
type Maybe a is not Nothing consists of just a function of type Maybe a
→ a existing. Why? Well, because if that Maybe a was Nothing, then it
wouldn’t be possible to obtain the a the function is supposed to
return, so the function wouldn’t exist. Other proofs, such as ours
here, are a bit more delicate because while these two fromEither and
toEither exist, their behaviour can’t be determined from their types.
Consider the following implementations instead.

fromEither :: Either Temperature Season -> ThisOrThat


fromEither = \_ -> This Hot

toEither :: ThisOrThat -> Either Temperature Season


toEither = \_ -> Right Summer

Those functions satisfy the expected types just fine, yet they don’t
contribute towards our isomorphism proof. Remember, we said
that two types being isomorphic means that it’s possible to convert
back and forth between them without any loss of information, but
our funny functions here certainly lose information. For example,
if they are given Winter as input somehow, then that Winter will be
ignored by the wildcard underscore _ and forever lost, replaced by
Hot or Summer. Our original implementations of fromEither and
toEither were correct and avoided this issue. Essentially, what we
were looking for was a pair of functions that, when applied after
each other, gave us back the same input that was provided to it.

Right Winter == toEither (fromEither (Right Winter))

That Winter == fromEither (toEither (That Winter))

The code above doesn’t contain Haskell definitions as we’ve seen so


far, that’s why we used the double equals sign == rather than the
usual single one =. We are simply asserting some truths. We are
saying that the things to the left of the == symbol are equal to the
things on the right. In other words, we are saying that applying
toEither after fromEither, or fromEither after toEither, gives us back
the input that was provided to it, unmodified. We’ve seen this
behaviour before, actually. This is exactly the same behaviour that
the identity function has. Yes, indeed. In precise words, these
functions, when applied one after the other, need to behave exactly
as the identity function, leaving its input untouched. Of course,
this equality needs to be true for all possible values of type Either
Temperature Season and ThisOrThat, not just for our minuscule Winter
selection.

So yes, to sum up, Either Temperature Season and ThisOrThat are


isomorphic, and using either one or the other would be equally fine
for our purposes. We can even switch the order of the Either
parameters to have Either Season Temperature instead, and the
isomorphism would still hold. Of course, we would need to rewrite
our proofs in that case to accommodate the different order, but
that would be too boring so we won’t do it today.
20. Pairs
In mathematics we have this fascinating idea of duality which more
or less says that some things have a dual that, intuitively, has the
opposite relationship with things than the original thing had. So,
the dual of an exit door would be an entry door, the dual of an
input would be an output, and the dual of a fuction a → b would be
a function b → a. Of course, following the proper mathematical
protocols to introduce new ideas, this is a very handwavy definition
of duality. We will revisit duality later on, but this poor definition
should more or less suffice for our current needs.

As we just saw, Either x y is making a statement saying that we have


one of two possible values of types x or y in it. It turns out that
Either, or sum types more generally, have a very reasonable and
useful dual construction in which we have both x and y. In Haskell,
we can convey this idea as well. Let’s call it Pair.

data Pair x y = MakePair x y

This definition shouldn’t be very surprising. Just like in Either x y,


here we are saying in Pair x y that x and y will be the types of the
values that will be part of our pair. That is, a pair of a Season and a
Temperature will have type Pair Season Temperature, for example. To
the right of the equals sign we have the constructor. Just one
constructor this time. And in it we see that x and y are its payload,
its fields. It’s easy to see how Pair and Either are dual: In Either we
are expected to pick one of two possible constructors, each of them
carrying a different payload. Here, in Pair, we have just one possible
constructor carrying both x and y as payload. There’s no choice to
be made, so if we want to build a Pair then we must provide both x
and y to the only available constructor MakePair.

This Make or Mk prefix is rather common when defining


constructors, it makes it easier to tell apart the constructor from the
type, something desirable at times. But it’s also quite common to
just reuse the same name for the type constructor and the value
constructor. This is fine, because from the point of view of the
compiler, types and values exist in two completely different realms,
so their names don’t overlap with each other.

data Pair x y = Pair x y

We will continue using this new definition so that we can get used
to differentiating between types and expressions by means other
than just their looks.

But of course, instead of using Pair Season Temperature we could


have introduced a datatype like PairOfSeasonAndTemperature
isomorphic to it, and use that instead. Sometimes that’s preferable,
sometimes it’s just silly. Technically speaking, datatypes such as
Pair and PairOfSeasonAndTemperature, where we have both this and
that, are called product types. This is a perfectly reasonable name if
we contrast it with the sum type name we already saw. While the
cardinality of sum types—that is, the number of possible values
that can have its type—equals the sum of the cardinalities of its
parts, the cardinality of product types equals the product of the
cardinalities of its parts. Well, more or less. We’ll study cardinality
in more precise terms later, but this definition suffices for now.
Anyway, 4 Seasons plus 4 Temperatures equals 8. That’s the number
of possible values the type Either Season Temperature can have, we
saw this before. 4 times 4, however, is 16, so 16 is the number of
possible values that the type Pair Season Temperature can have. Let’s
count them.

1. MakePair Winter Cold 9. MakePair Summer Cold


2. MakePair Winter Warm 10. MakePair Summer Warm
3. MakePair Winter Hot 11. MakePair Summer Hot
4. MakePair Winter Chilly 12. MakePair Summer Chilly
5. MakePair Spring Cold 13. MakePair Autumn Cold
6. MakePair Spring Warm 14. MakePair Autumn Warm
7. MakePair Spring Hot 15. MakePair Autumn Hot
8. MakePair Spring Chilly 16. MakePair Autumn Chilly

Counting from one is strange. You’ll get the joke later, but that’s all
16 of them. There’s no other value that can carry the type Pair
Season Temperature. And of course, these 16 values are the ones we
would need to pattern match against if we were doing some kind of
case analysis.

A sum type can be called by a different name as well: coproduct. The


co prefix in coproduct is the prefix we stick to things to say
something is the dual of that other thing. In coproduct we are saying
that this type is the dual of a product type. Which, of course, is true.
Technically we could say that product types are cosums as well,
since they are the dual of sum types. In practice, however, due to
tradition we don’t. Moreover, we have to stop somewhere, don’t
we? Otherwise we could end up with a cocococococoproduct in our
hands. That’s coconuts.
21. Dos
We say Either and Pair are fundamental because once we can group
or tell apart two things, we can group or tell apart as many things as
we want. How so? Well, we simply make one or two of their
payloads be yet another Either or Pair. For example, we can have
either a Natural or a Season or a String by simply having a type Either
Natural (Either Season String). That is, an Either where one of its
parameter is yet another Either. Constructing a value of such type is
straightforward, albeit noisy.

my_season :: Either Natural (Either Season String)


my_season = Right (Left Autumn)

That is, Right is saying that we’ll be providing a value for the
payload on the Right constructor of the outermost Either, and Left
is saying that we’ll be providing the a value for the payload of the
Left constructor of the inner Either. It should be quite easy to
appreciate visually how the parentheses on the type match the
position of the parentheses on the expression. Visual aids are always
welcome.

These payloads don’t need to be of different types, though. We


could have for example a Right (Left 5) of type Either Natural
(Either Natural Natural). If we look at these three Naturals from left
to right, no pun intended, then the one Natural we are providing
amongst these three is the second one.

We nested our uses of Either to go beyond the mere two payloads


we thought it could only handle before, and we can keep doing this
over and over, repeatedly nesting Eithers to have even more
payloads that way. However, it gets noisy quite rapidly. Sometimes
this is exactly what we want, particularly when we want to
generalize problems that deal with sum types of any size, but
usually we will define our own sum types just like we did with
Season and Temperature instead, whenever they have more than two
constructors.

Of course, we can nest Pairs as well. For example, if we want to


group a Natural, a Season and a String together, then we could do
the following.

my_things :: Pair (Pair Natural Season) String


my_things = MakePair (MakePair 5 Summer) "songs"

Notice that Pair (Pair x y) z and Pair x (Pair y z), or any other
permutation of x, y and z there, are types isomorphic to each other.
And the same is true for Eithers. That is, while these are different
types in the eyes of the type-checker, we can easily convert back and
forth between them without loss of information. For example,
here’s one such silly conversion, and we can easily imagine how the
one in the oposite direction would look like.

f :: Pair (Pair x y) z
-> Pair x (Pair z y)
f = \(MakePair (MakePair x y) z) ->
MakePair x (MakePair z y)

We are growing, aren’t we? Even our function types now span
multiple lines. That’s fine, nothing changes, it’s just a different use
of our whitespace. We mostly just need to make sure we always
indent our text to the right where otherwise we would have
continued on the same line.
It is of course possible to combine Pairs and Eithers as well. We
could have, say, in a type like Either (Pair Natural Season) (Pair
Season Temperature), either a Natural and a Season, or a Season and a
Temperature.
22. Tuple syntax
The Pair type isn’t present in the Haskell language exactly as we
introduced it. It’s there conceptually, sure, but out-of-the box we
get a different syntax for it. Rather than writing Pair a b, we write
(a, b). This notation for pairs is part of the Haskell language
syntax, and we couldn’t define it ourselves if we wanted to. It’s
quite sad that we have exceptions such as this, but at times it can be
practical. For example, whereas a product type of more than two
elements nesting our fundamental Pairs requires us to write Pair
(Pair a b) (Pair c (Pair d e)) or similar, using the built-in syntax
for pairs we can say (a, b, c, d, e), which is arguably easier on the
eyes. Of course, we could have introduced a new product type
capable of holding 5 arbitrary elements, say Pair5 a b c d e, and it
would have been as straightforward and specialized as this five-
element tuple, but without the extraordinary syntax.

Actually, this 5-element tuple approach is not entirely correct


because considering the order in which we nested our Pairs, the
direct translation to this syntax would be ((a, b), (c, (d, e))).
However, hopefully we can see that these two representations are
isomorphic to each other, so we can use whichever is more
convenient, which in the case of pairs, or tuples as they are also
known, is usually the one that looks more aesthetically pleasing,
even if it’s not made out of fundamental building blocks like those
two-element pairs.

So, if we wanted to group together a Season, a Natural and a


Temperature without giving an explicit name to the type of this
grouping, we could do so in a value of type (Season, Natural,
Temperature). And using the tuple syntax at the value level is quite
similar to using it at the type level. We simply mention values,
rather than types, as their elements.

three_things :: (Season, Natural, Temperature)


three_things = (Summer, 2, Hot)

Pattern matching on tuples is also quite straightforward. For


example, let’s write a function that adds together three Natural
numbers given as the elements of a tuple.

add3 :: (Natural, Natural, Natural) -> Natural


add3 = \(x, y, z) -> x + y + z

We are simply pattern matching on the special tuple syntax, if you


will, and binding its elements to the names x, y and z before adding
them.

As you will see later, this extraordinary syntax unnecessarily


complicates our learning for no significant gain. The pursuit of
clarity is our business, but this syntax is mostly a distraction. Yet
tuples, or anonymous product types as they are sometimes called, are
so ubiquitous in Haskell that we’ll embrace them in our learning in
spite of this. Ironically, there’s no special syntax for anonymous sum
types containing more than two elements in Haskell, so we are
forced to nest Eithers in order to accomplish that. In practice we
don’t, and instead we define and name a new sum type whenever
we need one.
23. Lists
The fact that tuples mention as part of their type how many
elements they contain can be either positive or negative, depending
on who we ask and what problem we are trying to solve. If we
know our program will somehow deal with a Natural and a Season at
the same time, then having the type (Natural, Season) show up
somewhere in our program is probably a good idea. However,
that’s not always the case. For example, let’s say we are asking
people to list their favorite Natural numbers. Someone says 3, some
have no favorite numbers, and somebody else likes 30, 99 and 1000.
How would we type these collections of values? Tuples won’t do,
because they would force us to know the size of each participant’s
selection beforehand, selections that understandably won’t always
agree on their size. Some like no numbers, some like some. No, we
need a more flexible type than a tuple, we need some kind of
container that can group together an arbitrary number of things.

A simple and rather beautiful container we can use to solve this


problem is the linked list. A linked list allows us to group together
zero or more values of the same type without informing the compiler
how many. Essentially, if we have a list of Naturals, say, the compiler
knows about the possiblity of there being zero or more Naturals
within this list, but that’s all it will ever know. How many values
end up inside the list is something that only concerns the expressions
that make up our program, such as the interaction with people
telling us about their favorite number selection at runtime.

We’ve actually seen something like this in Maybe already. If we try


hard enough, we can see how Maybe Natural conveys the idea of a list
of just one Natural number, possibly empty, where in Nothing we
have the empty list, and in Just 7, for example, we have the one-
element list containing number 7. Can we build on top of this
knowledge? Of course, building on top of previous knowledge is
what our type of programming is all about. Let’s recall Maybe.

data Maybe a = Nothing | Just a

In other words, Maybe is a coproduct or sum type wherein one of its


constructors, Nothing, conveys the idea of the list being empty, and
the other one conveys the idea of there being some a in the list.
How do we go about having more than one element in that list,
though? We can try and imagine what it would look like if we were
able to add more constructors to Maybe, each one listing a larger
number of as as its payload.

data Maybe a
= Nothing
| Just1 a
| Just2 a a
| Just3 a a a
| Just4 a a a a
| Just5 a a a a a
| … more of these …

However, there would be various problems with this. For one, we


seem to be writing just too much code, and while there’s no official
correlation between these things, you would be surprised at how
many times having too much code is the first symptom of a poorly
understood problem. The main issue, semantically, is that no
matter how many constructors we add to our Maybe type, they will
never be enough to contain an arbitrary and unknown number of
elements. Imagine we list one million constructors in this silly type
and then somebody comes with a selection of one million and one
values to put in it. They just won’t fit, even if we are only off by
one. No, explicitly listing the constructors is a terrible idea. We
need something else.

What we want is to be able to say that no matter how many


elements our list has so far, we should always be able to add one
more if necessary. Think about it. We are saying, in other words,
that our list can grow unboundedly. How do we accomplish this,
though? Well, to begin, we will need a leap of faith to trust that
what we are about to see is indeed possible.

data List a = Empty | OneMore a (List a)

We are defining List as a coproduct with two constructors. One of


them, Empty, obviously conveys the idea of the list being empty as
evidenced by the lack of any field of type a in it, where a, of course,
is the type of each individual element in the list. The other
constructor, OneMore, has two fields. One of them is a plain a, which
like in the Just constructor is the element that goes into the list. So
far this is just like Maybe. What’s fascinating is what happens in the
second field of this constructor, where we mention yet another List
a as the type of this field. The idea is that if the List a in this field
contains, say, three elements, then the OneMore constructor will pair
it with a standalone a to create yet another List a. But you see, we
haven’t yet finished defining what a List a is at the time we refer to
it from this constructor field. Yet here we are, with a Haskell
compiler that is more than happy to accept our definition of the
List datatype as valid. Stop for a second, contemplate and ponder
as the philosopher would. How is this possible? What does it mean?

This datatype talks about itself in a way we hadn’t seen before. We


say that List a is a recursive datatype. That is, a datatype whose
definition mentions itself by name. Let’s see how this looks in
practice. Let’s start from zero.

Empty :: List Natural

No surprises so far. Similar to Nothing, we know that Empty is a value


of type List a for any a of our choosing. Here, we pick a to be
Natural, conveying the idea that our List contains Natural numbers.
And now, following our original recommendation that we can
always add one more element to our list, let’s use the OneMore
constructor on our Empty list to add one more element to it, 8.

OneMore 8 Empty :: List Natural

Notice the type. It’s still a List Natural even though the constructor
is a different one. How come? Well, List a is a coproduct, so we
know we can construct one using any of its constructors. Empty was
one such constructor, but OneMore is one as well. OneMore takes our
new element 8 as payload alongside our Empty starting point, which
fit the expected Natural and List Natural types of the constructor
fields just fine. Can we go further? Of course we can, this was the
plan all along. Let’s add the element 5 to the list.

OneMore 5 (OneMore 8 Empty) :: List Natural

Still the same type, still the OneMore constructor, still a value of type
Natural, 5, in the first field, and a value of type List Natural in the
second field. We can repeat this until we get bored. We can
continue applying the OneMore constructor to this List, and each
time we do we are effectively making room for yet another value of
type Natural to become part of the list.
Linked lists belong to the classic literature of programming, thus
we’ll refrain from blasphemy and use the names historically given
to its constructors, Nil and Cons, rather than the Empty and OneMore
names that served our didactic pursuit so far. Remember, the
compiler doesn’t care about names, but we and our colleagues do.

data List a = Nil | Cons a (List a)

Nil, chiefly poetic, in Latin meant nothing. Cons, austere and


arguably hip, comes from the Lisp family of programming
languages where it stood for “constructing a pair” before becoming
pop culture.
24. Induction
Recursion comes in different shapes. Our List is what we call an
inductively recursive datatype, a beautiful thing which we’ll explore
now.

We’ve been told that natural numbers are infinite. But we, people
of science, trust nothing but our thirst and our proofs. Thus we’ll
corroborate this lore ourselves using induction.

A natural number, we said, is either zero or any integer number


bigger than zero. And either and or, we know, are the first signs that
a coproduct is due. We’ll call our coproduct Nat to avoid mistaking
it with the Natural that already comes with Haskell.

One of the constructors for our Nat datatype will be Zero, which,
akin to the Nil in our previous List, takes no payload and represents
the smallest Nat. When we say smallest, however, we are not
referring to the fact that zero is indeed numerically smaller than
every other natural number, which happens to be a coincidence.
Rather, we mean that zero can be said to be a natural number
without having to relate it to yet another natural number. It has the
smallest structure, or smallest number of relationships, if you will.
If we recall our definition of natural numbers again, we said that
they are either zero or any integer number bigger than zero. So, if
we were to justify why the integer number five is also a natural
number, we’d have to say “because it is bigger than zero”, whereas
the reason why zero is a natural number is just “because”. Can we
see the difference? Five is a natural number because its relationship
with another natural number says so, zero is a natural number
because it is zero and that’s the base case, the starting point from
where we can start talking about natural numbers.
If we contrast this with another inductive datatype, the negative
integers, which are -1 and every other integer smaller than -1, then
-1 would be the smallest or base case in our induction, even if from
a numerical point of view the number -1 is actually larger than
every other negative integer. Inductive datatype definitions always
start from a base case, which in the case of our List it was Nil, and in
the case of our Nat it is Zero.

The second part to our induction should come as no surprise given


our experience defining List. Let’s look at the full definition of Nat
now before proceeding.

data Nat = Zero | Succ Nat

Other than the word succ standing for successor and inviting us to
wonder whether we ever stop to read abbreviations out loud lest
they don’t stand scrutiny, Succ should immediately remind us of
Cons, the inductive constructor in our definition of List. What Succ
is saying is that no matter what Natural number we have, we can
obtain its succesor —that is, the natural number immediately after
it— by applying the Succ constructor to it. Let’s count to three to
see how this works.

zero = Zero :: Nat


one = Succ Zero :: Nat
two = Succ (Succ Zero) :: Nat
three = Succ (Succ (Succ Zero)) :: Nat

All of these values are perfectly valid natural numbers, as witnessed


by the explicit type information we are giving when we say :: and
then Nat, an alternative Haskell notation used to explicitly give a
type to expressions right where they are used. We could also have
written the types on their own lines as we have been doing so far,
and it would have meant the same. Not important.

zero :: Nat
zero = Zero

one :: Nat
one = Succ Zero

two :: Nat
two = Succ (Succ Zero)

three :: Nat
three = Succ (Succ (Succ Zero))

We are saying here that we’ll name Zero “zero”, that we’ll name “
one” the Successor of Zero, that we’ll name “two” the Successor to the
Successor of Zero, etc. We are, essentially, counting how many times
the Succ constructor is used. This gets tiresome rather quickly,
however, which is why by using the power of name binding we
could clean up things a bit if we wanted to.

zero = Zero :: Nat


one = Succ zero :: Nat
two = Succ one :: Nat
three = Succ two :: Nat

Naming things wasn’t our goal, though. Proving that natural


numbers are infinite was. And indeed, we have proved this. The
inductive definition of Nat itself is the proof. It says that we can
always obtain the Successor of a Natural number, no matter how big
that natural number is. Many things in mathematics can be proved
or defined by induction, which makes definitions like Nat's even
more appealing to us programmers.

And finally, perhaps a more interesting way to define natural


numbers now that we understand induction, is to say that a natural
number is either zero or a natural number plus one.

Do you get the joke now about counting from one now? It’s
strange. We programmers, naturally, always count from zero.
25. Representation
Haskell’s Natural and our Nat are not exactly the same. Say, if we
apply a function expecting a Natural to Succ Zero, the type-checker
will reject it. Conceptually, though, they are “the same”. That is,
they are isomorphic to each other. They carry the same meaning, so
no information would be lost if we were to convert between them.
Let’s implement these conversions so that we can convince
ourselves that we did a good job.

First, let’s understand a bit more about Haskell’s support for


Natural numbers as literal digits. In Haskell, when we use a literal
digits expression like 123 where a value of type Natural is expected,
the language will convert those three digits to a Natural for us. It’s
not important how this happens, but it’s important to know that
this, more or less, is the only way we have of constructing a Natural
value out of thin air. Natural numbers, we learned, are conceptually
an inductive construction. Nevertheless, we don’t get to see how
the Natural datatype itself is defined in the Haskell language
because, by design, it’s “up to the language implementation” to
decide how to do so. Were we creating a new implementation of
the Haskell language, we could say that 123 should be converted to
123 applications of Succ. In practice, that’s something we’d like to
avoid at all costs for performance reasons, as most implementations
of the Haskell programming language do, including GHC which is
the one Haskell implementation we pay attention to in this book.

The problem with Nat, List, and a myriad of beautiful


constructions we’ll encounter in life, inductive or not, is that our
computers are terribly inefficient at working with them. Picture
yourself facing a piece of paper with the digits “25” written on it.
These digits take a rather small amount of space on our paper, and
moreover, recognizing their meaning as the natural number 25
requires very little effort from us. On the other hand, if we were to
encounter 25 Succs written down, understanding their meaning
would require a bigger effort from us, as we’d need to manually
count how many Succs we are facing before saying “ah, it’s the
natural number 25”. And, font size being the same, it would
definitely take up more space on our piece of paper. Computers are
no different in this regard. In this analogy, the size of our paper
represents how much memory our computer has, memory wherein
representations of data are written. The effort it takes to derive
meaning from those representations corresponds to how
performant a representation is. That a computer would need to do
at least 25 things in order to convey the idea of the number 25 is
unacceptable, no matter how fast the computer might be. Because,
while 25 is a relatively small number and it doesn’t seem that bad to
write down Succ 25 times, using this representation with larger
numbers like seven trillion would require seven trillion Succs to fit
in memory and seven trillion times we’ll need to see Succ appear
before we can do something useful with that number. It is indeed
ridiculous. We say that Nat is a representation for natural numbers
whose time and space complexity grows linearly with the number it
represents. That is, the bigger the number, the bigger the time and
space we’ll be dedicating to understanding it.

So we make this compromise: We can inductively reason all we


want about our natural numbers using a representation like Nat for
didactic and research purposes, but we are encouraged to convert
between Nat and Natural at some point, to leverage the more
efficient representation for natural numbers when pursuing a
practical goal like multiplying numbers or parsing them from a
String. So let’s implement that conversion once and for all. First,
let’s convert from Nat to Natural.
fromNat :: Nat -> Natural
fromNat = \x ->
case x of
Zero -> 0
Succ y -> 1 + fromNat y

The first thing to notice should be the blatant recursion going on


here, wherein we refer to this function’s name, fromNat, from within
fromNat's own definition. Yes, both datatypes and functions can be
defined recursively.

fromNat is saying that given a Nat, which we will call x, we return the
Natural value 0 in case x is Zero. Otherwise, if x Succs, we add 1 to the
result of applying fromNat to y, the name given to the Nat field in the
Succ constructor. What we are doing, essentially, is adding 1 each
time we encounter the Succ constructor, peeling the Succ layers one
by one until we finally reach our base case Zero and the recursion
stops. For example, fromNat Zero would lead to 0, fromNat (Succ
Zero) would lead to 1 + 0, fromNat (Succ (Succ Zero)) would lead to
1 + 1 + 0, etc. Grab a pencil and a piece of paper and try to do this
same exercise yourself: Follow the transformation of fromNat (Succ
(Succ Zero)) step by step until it becomes 1 + 1 + 0.

The conversion from Natural to Nat is not that different:

fromNatural :: Natural -> Nat


fromNatural = \x ->
case x of
0 -> Zero
_ -> Succ (fromNatural (x - 1))

What changes, mainly, is that we can’t pattern match on anything


like Succ in order to obtain the input to our recursive call to
fromNatural. This is because x is a Natural, not a Nat, and Naturals are
constructed using literal digits like 3 or 12, not using Succ nor any
other recursive constructor. So we need to perform x - 1 by hand
to obtain the number that comes before x, which is necessary for
our recursive call to fromNatural. Previously, in fromNat, it was the y
in Succ y conveyed the idea of x + 1, but here we can’t have that
because we are not pattern matching on Nats, but on Naturals. Once
we have this x - 1, we can proceed to recursively call fromNatural
and use its result as the payload to Succ. So, as examples, fromNatural
0 becomes Zero; fromNatural 1 becomes Succ (fromNatural 0), that is,
Succ Zero; and fromNatural 2 becomes Succ (fromNatural 1), which
in turn becomes Succ (Succ (fromNatural 0)) to finally become Succ
(Succ Zero).

Despite these small differences, the similarities between these two


implementations highlight the inductive nature of natural
numbers, even if Nat and Natural have a different implementation
internally.
26. Halt!
It’s a tricky thing, recursion. It is, essentially, what tells computers
apart from every other machine, but it comes at a very high cost.
Let’s consider what would happen if instead of writing x - 1 in our
implementation of fromNatural, we had written x + 1. Applying
fromNatural to 0 would return Zero as expected. However, applying
it to any other Natural value would lead our program into an
infinite loop, a loop that would never finish. This is how the
evaluation of fromNatural 1 would go: The function would return
Succ applied to fromNatural 2, which would return Succ applied to
fromNatural 3, which would return Succ applied to fromNatural 4,
etc. That is, instead of getting closer to 0, the base case through
which we would finally exit our function, we would be getting
farther and farther away from it on each iteration, ad infinitum.
This is bad. In practice, it means that our program will likely hang
at some point. We say that our broken fromNatural is a function that
diverges, a function that never finishes executing.

Unfortunately, Haskell’s type-checker can’t help us here. The type


of our broken fromNatural is still Natural → Nat, and the type-checker
happily accepts its implementation. This isn’t Haskell’s fault,
however. This is a fundamental limitation in the theory of
computation called the halting problem, which states that it is
impossible to determine programmatically whether an arbitrary
program written in a general purpose programming language halts
or not. That is, whether a program written in a programming
language able to express any computable problem will finish
executing or not. Of course, we humans can manually observe and
analyze our programs to determine whether they halt on a case-by-
case basis, just like we did when we compared the broken
fromNatural to the correct one. But it wouldn’t be possible for us,
nor for the authors of the Haskell programming language, to write
a general program or compiler that can tell whether we’ve
accidentally written something that would never finish executing.

But to a great extent this makes sense, actually, considering that


halting is not a necessary precondition to being a useful program.
Think of traffic lights, for example. They run unconditionally, they
never halt, yet they are productive and provide immense value to
society while they run. A so-called general purpose programming
language, thus, should allow us to build traffic lights at least.

There are specialized programming languages that abandon their


general programming capabilities —which in practical terms
mostly means abandoning support for general recursion— and in
return they can tell us whether the programs we write with it will
halt or not. Haskell as a whole is no such language, but we’ll see and
build languages where this is true later on, within and outside
Haskell.
27. Too much
We’ve learned a lot, but we’ve also learned too much. All the
problems we solved so far, we could have solved using just
functions. Let’s get rid of the decor, the convenience, and go
primitive, down to the very essentials of functional programming.

We talked about general programming languages before. We said


these are the languages that allow us to express any computable
problem. What does this mean, though? What are computable
problems? People have been asking themselves this same question
for a long time, and it wasn’t until the 1930s that they came up
with rather intriguing answers in the form of machines comparable
to the programming languages of today. These are machines that at
first seem rather insufficient, having only a handful of functions
they can perform. One wouldn’t dream of building a complex
program in these machines, it would be terribly inefficient. Yet,
past their austerity, these machines are fundamental. They
comprise the minimum set of features required to compute
something. No matter how complex the solution to a problem may
be, as long as it can be computed, it is possible to express it in a way
these machines can understand it. Every general programming
language out there, notwithstanding any extra bells and whistles
offered, can at most offer the same computation capabilities as
these machines. They just do so in a gentler and more ergonomic
package.

One such machine, close to our hearts and to everything we’ve seen
so far, is the lambda calculus, stylized λ-calculus if leveraging the
beautiful Greek alphabet. We will build this machine now.
28. λ-calculus
Building a lambda calculus can be a tough exercise, but by doing so
we’ll come to appreciate one of the core ideas of functional
programming: That however complex a problem might seem at
first, however different from everything else we’ve seen before, it
can always be broken down into more fundamental problems that
can be tackled separately, problems that quite often we’ve already
solved before.

It’s OK to feel a bit lost here. We are not learning this because we
need it right away, we are learning it so that we can demystify the
complexities of this field, understand that we are in control, and
scare away any silly ideas that we are not capable of tackling what’s
to come. We are welcome to find solace somewhere else, too, if that
works.

Let’s forget about types while we are here. In our lambda calculus,
initially, we will only be concerned about expressions. Our lambda
calculus tells us what kind of expressions we can use, how, and
what they mean. In its most rudimentary form, an expression in the
lambda calculus is one of three things: It’s either a reference to a
value, just like the names we have in Haskell; or it is a lambda
expression not unlike the ones we have in Haskell; or it is the
application of an expression to some other expression, much like
our own function applications in Haskell. Either, or, or; we know
what that calls for: A sum type, which we will call Expr as a short for
expression.
data Expr
= Lookup String
| Lambda String Expr
| Apply Expr Expr

Behold: Computer. Yes, that is the entire definition of our simple


lambda calculus, of what is computable. What’s going on is perhaps
best explained by looking at some examples, so let’s write the
simplest possible program using our lambda calculus: The identity
function.

expr_id :: Expr
expr_id = Lambda "x" (Lookup "x")

It’s important to understand that because we are using Haskell to


implement our lambda calculus, we will be naming and referring to
expressions of type Expr in Haskell, but ultimately those expressions
are intended to be exploited by an interpreter for our lambda
calculus, not by Haskell itself. For example, our expr_id is indeed a
valid Haskell expression, but more importantly, it’s a valid
expression in our lambda calculus as well, akin to Haskell’s own
identity function.

id = \x -> x

The Lambda "x" part in expr_id corresponds to \x → in id, and the


Lookup "x" part corresponds to the x that shows up to the right of
the arrow symbol → in id, where we refer to the value of x, whatever
it may be, by a name. The correspondence between Expr and
Haskell is quite literal in this case, something that shouldn’t be
surprising at all considering how these are called lambda expressions
in Haskell. Lambda "x" is saying that expr_id will be a function taking
one parameter as input, which we will call “x”. As usual, “x” is an
arbitrarily chosen name which could have been anything else. The
second field of the Lambda constructor is yet another Expr
corresponding to the body of the function we are defining. In this
case, the body just looks up the value bound to the name “x” by the
Lambda constructor and returns it, as expected.

Applying this newly defined function is generally quite easy. Expr


has a constructor called Apply that, presumably, applies the Expr
value in one of its fields to the Expr in the other field. This is the
same thing that the juxtaposition of expressions accomplishes in
Haskell. All we have to do is use it. However, there is an issue.
While we know how to define a function, as we did in expr_id, and
while we know how to apply it to some other expression using the
Apply constructor, we don’t necessarily know how to come up with
that other expression to which to apply expr_id. Imagine we want
to apply expr_id to the number five. Well, how do we represent five
as a value of type Expr? It’s not immediately obvious if we consider
that Lambda, Lookup and Apply are all we have available. It is indeed
possible to represent five, numbers, products, coproducts, lists or
any other value we might need with what we have using only the
Expr constructors. Doing so, however, is much more complex than
our current needs warrant, so we’ll just not do it for the time being.
Let’s cheat instead.

Since we can’t yet explain how numbers come to be, let’s just
assume that somebody, a superior being, created the number five
for us and bound it to the name "five" by saying Lambda "five". We
can refer to this number while remaining deliberately oblivious of
the complex truth by looking it up by name using Lookup "five". So
now we have Lookup "five", a value of type Expr that magically
means something. How do we apply expr_id to it? Well, we just use
the Apply constructor with expr_id as its first parameter and Lookup
"five" as the second.

expr_five :: Expr
expr_five = Apply expr_id (Lookup "five")

Now expr_five and our mystical Lookup "five" have exactly the same
meaning, just like 5 and id 5 mean exactly the same in Haskell. We
have accomplished a function application in our Expr lambda
calculus.

But wait. Actually, we could have avoided all this mystical mess by
simply realizing that expr_id is itself already a value of type Expr, and
that while Apply needs two values of type Expr, it says nothing about
whether they need to be different. So we might as well use expr_id
twice. What would be wrong with saying Apply expr_id expr_id?
Nothing. There would be nothing wrong with that. It conveys
exactly the same idea as id id does in Haskell, a function
application whose main purpose seems to be to deepen our already
profound appreciation for the beauty of the identity function,
when we realize that id id is also the identity function.

id == id id

We follow the types and we find beauty.

So let’s get rid of the idea that programming is hard or impossible


to tackle. Programming welcomes everyone. This discipline can be
reasoned about, and that’s beautiful. If we commit ourselves to
pursuing an understanding, most answers will always be in front of
us. We need to look hard, we need to follow the types. And if we
can’t see the answers yet, we can always break down the problems
into smaller parts until we can. Otherwise, chances are we have
failed to properly identify the problem to solve. Or perhaps we are
simply at the boundaries of knowledge, about to discover
something new, in which case we must go even further.

But we will put our lambda calculus on standby for now. We don’t
really need to understand how to interpret or calculate these Exprs
just yet. Simply knowing that it can be done, and that
programming is just functions all the way down, should put our
minds at ease. We will come back to this topic later when it is time
to implement our own programming language. For now, let’s go
back to our more immediate goal of becoming proficient in
Haskell.

id == id id id id id id id id id id id id id id id id
29. List syntax
Let’s look at linked lists once more. They will accompany us for a
very long time in our learning, as their simplicity and inductive
nature make them an excellent structure for didactic and practical
purposes.

Linked lists —or just lists as we usually call them— are so


ubiquitous that in Haskell, for better or worse, they have their own
special syntax like tuples do. Instead of saying Cons 1 (Cons 2 (Cons
3 Nil)) as we would do were we using our own List datatype,
which we introduced a couple of chapters ago, we would say [1, 2,
3]. Notice the square brackets, rather than the parentheses you see
in the similar special notation for tuples. An empty list is
represented by two square brackets hugging each other, []. Their
love story doesn’t end there, however.

It wouldn’t be sufficient to only have this [a, b, c] notation


because, remember, the interesting thing about linked lists is that
they can grow. That is, we need something comparable to Cons that
we can use to grow our list. Haskell provides us with a constructor,
awkwardly named :, that we can use to grow our list. To add the
element 5 to a list of Natural numbers —whose type, by the way, is
not List Natural anymore but [Natural]— we write 3 : []. Writing
[3] would have achieved the same, but then we wouldn’t have
accomplished our goal of explicitly consing the list to grow it. And
yes, it is strange that we are writing the : symbol in between 3 and
[]. We will learn more about this later, but essentially, : is just like
the Cons constructor, except one of its parameters appears to its left
and the other to its right, rather than both of them appearing to its
right as they do with Cons. We can repeat this again, say, to add the
numbers 1 and 2 to this list by writing 1 : 2 : 3 : [], which again is
the same as [1, 2, 3].

Once more we apologize for this noise distracting us from our


learning, but this is what we’ll be dealing with and we need to
memorize it. Verbally, however, because sometimes we must talk
with our colleagues out loud about these things, we call [] the
empty list or nil, and we call : cons, so not everything is lost.
30. Mapping
So let’s imagine we have a list with some numbers, [3, 4, 5], and
have been tasked to increase each of them by one.

add_ones :: [Natural] -> [Natural]


add_ones = \[a, b, c] -> [a + 1, b + 1, c + 1]

We are pattern-matching on the special list syntax. We haven’t


done this before, but it shouldn’t be surprising considering how we
pattern-matched on the special syntax for tuples before, which was
almost the same. Here we have square brackets [ rather than
parentheses ), that’s all.

Yes, add_ones [3, 4, 5] will indeed result in [4, 5, 6], adding one to
each element as we wanted. But, in all honesty, add_ones is a rather
sad thing. For one, it’s assuming a list of three elements. This works,
alright, but what happens if we apply this function to something
else like [1, 2] or to the empty list []? Boom. Our program crashes
at runtime, the passengers on the plane die. Luckily, Haskell’s type-
checker will tell us about our non-exhaustive pattern-matching and
prevent this program from compiling, so mistakes like that one are
easy to avoid. A second and more subtle issue is that we are writing
the same operation, the addition of 1, three times. This is
manageable here, but imagine how lengthy and sad it would be
having to do the same for a list of, say, 100 elements.

Functional programming, we learned, is all about functions. And


functions, we know, are about not repeating ourselves. About not
repeating ourselves. Functional programming wants us to say “add
one to each element of the list” rather than literally writing the same
addition to each element of the list over and over again. Functional
programming gives us —or rather, allows us to create— a
vocabulary where functions can take other functions that
determine part of their behaviour as input. Functional
programming actually begs us to say “do something to each element
of the list”, where adding one, much like subtracting three, could
be that something. It’s called mapping.

map :: (x -> y) -> [x] -> [y]

We call functions like map, taking other functions as input, higher-


order functions. The type of map, whose name has nothing to do
with cartography, says that given a function from a value of type x
to a value of type y, and a list of said x values, it will return a list of
values of type y. Internally, map will apply the given function to each
element of the given list individually, effectively transforming each
x value into one of type y.

map :: (x -> y) -> [x] -> [y]


map = \f xs ->
case xs of
[] -> []
x : rest -> f x : map f rest

We haven’t pattern-matched on the : constructor before, but


hopefully it won’t be too surprising. map takes its two parameters as
input and pattern-matches on the second one, the [x] list, to decide
how to proceed depending on whether the list is empty or not. If
the list is empty, as witnessed by a successful pattern-match on the
[] “nil” constructor, then it simply returns yet another empty list.
This makes sense if we consider that the whole purpose of map is to
transform the elements of the list somehow, and that there would
be no elements to transform in an empty list. Thus, an empty list
result is due. The second pattern tackles the non-empty list scenario
by pattern-matching on the : “cons” constructor, which says that
the list has at least one element, which we are calling x here, and
then comes the rest of the list, which itself may or may not be
empty. What’s interesting is what happens to the right side of the
arrow →, where we use the : constructor once again to actually
construct a new list. The first element, to the left of :, is a value of
type y obtained by applying the given function f to x, a value of
type x. To the right of the constructor : we recursively apply map to
transform the elements remaining in the rest of the list in the same
fashion. Eventually, by the inductive nature of a linked list, we
know we will reach the empty list case and map will finally stop
recursing. Oh, and by the way, those parentheses around f x : map
f rest are superfluous. We put them there because there’s
something aesthetically pleasing about the left and right-hand-side
of a pattern in a case expression looking similar. The ones on the
left are mandatory, yes.

Let’s look at the implementation of map using our own List rather
than Haskell’s own weird list syntax, lest we get distracted by it and
miss the point of map.

map :: (x -> y) -> List x -> List y


map = \f xs ->
case xs of
Nil -> Nil
Cons x rest -> Cons (f x) (map f rest)

One by one, we are applying f to the elements of the given list,


constructing a new list with the same number of elements, in the
same order, in return. So, how do we add one to each element of
this list? Well, we simply map add_one over some list of numbers.
Remember, x and y on map's type are just type parameters that could
become anything: We could map a list of Seasons to a list of Strings, a
list of Naturals to yet another list of Naturals as we desired, or
something else.

add_ones :: [Natural] -> [Natural]


add_ones = \xs -> map add_one xs

Effectively, add_ones [3, 4, 5] equals [4, 5, 6].


31. η-conversion
There is some redundancy in our recent definition of add_ones as \xs
→ map add_one xs. The type that map takes in our very specific case is
(Natural → Natural) → [Natural] → [Natural]. As soon as we provide
the first input parameter to map, as in map add_one, we are left with an
expression of type [Natural] → [Natural] waiting for the second
input parameter to map. Our function add_ones creates a lambda
expression around map add_one that captures as xs that second input
parameter so that it can pass it to map add_one. That is, this lambda
expression takes its input only to reuse it as the very last thing to the
right of the → arrow. The type of this whole lambda expression is
[Natural] → [Natural], just like the type of map add_one was. But, if
both map add_one and \xs → map add_one xs have the same type and
behavior, can’t we just drop that seemingly redundant lambda
expression?

add_ones :: [Natural] -> [Natural]


add_ones = map add_one

Yes, we can. We call this the pointfree style of defining a function.


Sometimes, having one less name like xs to worry about can be
helpful. Other times it might be pointless, and writing the full
lambda expression would make the function definition a bit more
obvious to the reader, particularly when it involves a rather long
expression.

Saying either f or \x → f x means exactly the same. This fact has its
roots in the concept of Eta-conversion, stylized η-conversion, which
essentially says that this is possible. We sometimes refer to the silly
version of a function, that is, to the one allegedly unnecessarily
wrapping it in an extra lambda expression, as its η-expanded form.
It’s OK to forget this name, however.
32. Partial application
We say that map is partially applied inside our pointfree definition
of add_ones, meaning not all the parameters map was expecting have
been provided yet, only part of them have.

Partial application works beautifully in Haskell because when we


see a function type like a → b → c → d, what we are actually dealing
with, even if we can’t readily see it at first, is a function with type a
→ (b → (c → d)). That is, there is no such thing as a function taking
two parameters, or three, or any number of parameters other than
one. Functions always take one parameter and return something
right away. It just so happens that, at times, the thing functions
return is yet another function, thus we are fooled into believing a
more comfortable lie. a → b → c → d is not a function that takes
three parameters —a, b and c— as input, and returns d as output.
No. a → b → c → d, by which we actually mean a → (b → (c → d)), is
a function that takes an a as input and returns a function b → (c →
d) as output, which in turn takes a b as input and returns a function
c → d as output, which in turn takes a c as input and finally returns
a d as output. We rarely write down those parentheses because of
how comfortable we are without them, but they are always there.

And actually, something similar happens when we use a lambda


expression to define a function. Supposedly, we write things like \a
b c → d when we are defining a function that takes “more than one
parameter” as input. But we just said taking “more than one
parameter” is not really a thing, so what’s happening? Well, \a b c
→ d is mostly just a more comfortable, magical syntax for writing \a
→ (\b → (\c → d)), which is rather ugly. Of course, unsurprisingly
by now, those parentheses are superfluous as well, so we could say
\a → \b → \c → d which is arguably a bit easier on the eyes.
Now that we’ve learned the truth about functions and lambda
expressions, for practical reasons, we can go back to lying to
ourselves about functions taking “more than one parameter”.

So when we made it sound like map add_one was special, it wasn’t.


The actual type of map, insofar as our add_ones exercise is concerned,
is (Natural → Natural) → ([Natural] → [Natural]). Look at those
extra parentheses. That is, we can apply map to a function of type
Natural → Natural in order to obtain yet another function of type
[Natural] → [Natural], which is exactly what we wanted add_ones to
be.

Taking this even further, one could argue that add_ones doesn’t even
deserve its name. We might as well use map add_one directly as in map
add_one [2, 3] to obtain [3, 4] as result. Well, actually, we don’t
even need to name add_one. We could just partially apply our add
function of type Natural → Natural → Natural as add 1, obtaining yet
another function of type Natural → Natural which we could use as
the first parameter to map. We can say [3, 4], we can say map (add 1)
[2, 3], or we can say map add_one [2, 3], and it’s all the same.
What’s more, we can also say map (add 2), map (add 3) or similar for
slightly different results.
33. Bliss
Of course, we can’t confirm nor deny what is map's behaviour
judging solely from its type. According to it, this could be a
perfectly acceptable definition of map:

map :: (x -> y) -> [x] -> [y]


map = \_ _ -> []

Sure, why not. We are discarding the input we receive and


returning a perfectly acceptable [y] list. The type-checker, happy
enough, accepts this definition. There’s nothing wrong with it.

This problem is not new, we have seen it before. This is a situation


that happens whenever we know too much about something. In
software, knowing is a curse. We want to build things in such a way
that we know as little as possible about what we are dealing with,
lest we accidentaly accomplish something undesirable. We are liable
for the deeds of our software, but we can reduce that liability
through planned ignorance.

The concrete problem is that while mapping only requires us to


know how to find every x so that we can replace it with a y, here we
know other things as well. Particularly, we know that the place
where we are looking for these x values is a list, which in turn grants
us the knowledge of how to construct a list, which we can leverage,
accidentally or not, to construct one that satisfies the expected type
without actually satisfying the expected behaviour of the function.
We need something else. We need to convey the idea that
something can be mapped over, without actually saying what that
something is.
34. Typeclass
Enter typeclasses. A typeclass, as the name more or less suggests,
represents a class of types that supports some particular operations.
In the case of mapping, we will concern ourselves with the class of
types in which we can find values of a particular type that can be
replaced by values of a potentially different type. This is exactly
what our correct map did, but the problem with map was that it
talked concretely about lists when it mentioned those square
brackets in its type, and we want to avoid concrete stuff. Haskell
comes with a function called fmap that solves this problem.

fmap :: Functor f => (x -> y) -> f x -> f y

If we compare the type of fmap with the type of map for List, we shall
notice a striking similarity.

fmap :: Functor f => (x -> y) -> f x -> f y

map :: (x -> y) -> List x -> List y

Essentially, f seems to have replaced all occurrences of List, and a


new Functor thing seems to be talking about f somehow. Indeed,
that is what is happening. List x says that, potentially, there are
values of type x to be found inside a List x. Similarly, f x is saying
that, potentially, there are values of type x to be found inside f x,
whatever f x might be. But what could f x be? That is what Functor
f, to the left of the fat arrow symbol ⇒ is constraining.

Functor is the typeclass in question. Functor f is saying that the f type


parameter appearing to the right of the fat arrow symbol ⇒ can be
any type as long as it belongs to the class of types that implement
the features required by the Functor typeclass. Functor is the name
we give to these things that can be mapped over, such as Lists. It is a
beautiful name we’ll come to cherish, functor, although initially it
will seem completely unrelated to the idea of mapping over
something. Indeed, that we can map is just a consequence of a more
fundamental, beautiful design.
35. Functor
What is this Functor typeclass in concrete terms? Well, Functor comes
out of the box with Haskell, but we can try and reproduce its
definition here for didactic purposes. Let’s dive into some new
Haskell notation by looking at the full definition of this typeclass.

class Functor f where


fmap :: (a -> b) -> f a -> f b

This notation is introducing a new typeclass, as hinted by the class


keyword. The typeclass is called Functor. The f that comes
afterwards is a placeholder for any type that can implement
whatever it is that the Functor typeclass requires. And what does it
require? That a definition for fmap be given. We will do that soon.

We said before that the type of fmap was Functor f ⇒ (a → b) → f a →


f b, and it was the Functor f constraint which caught our attention.
However, we don’t see this Functor constraint on f anymore when
we give a type to fmap in our typeclass definition. The reason for this
is that this constraint is already implicitly required by the fact that
fmap is part of the Functor typeclass definition itself. If there were
any additional constraints on f, a or b, then we would need to
explicitly mention them somewhere, but that is not the case here.

So we are saying that for some arbitrary type f to belong to the class
of types that can be mapped over, which we call the Functor class, it
must implement the fmap method. Yes, fmap is technically just a
function, but the fact that its type is defined as part of a typeclass
makes it deserve the special name “method”, presumably for us
humans to have an easier time talking about it out loud. But
functions, we know, have both a type and a definition. Here,
however, we can only see its type. Where is its definition? Where is
the expression that defines what fmap actually does?
36. Instances
There is only one class called Functor, but there are potentially many
types that satisfy the requirements of that class. That is, types that
can be mapped over. We know of at least two: Our own List, and
Haskell’s own list with that weird square bracket [] syntax. We
establish the relationship between typeclasses and the types that can
implement them through instances. In instances, that’s where fmap's
implementation lives. Let’s write the Functor instance for our List
type.

instance Functor List where


fmap = \g xs ->
case xs of
Nil -> Nil
Cons x rest -> Cons (g x) (fmap g rest)

In instance Functor List we are saying that what follows, indented a


bit further to the right, is the implementation of the instance of the
Functor typeclass for the List type. There can only be one instance
of a particular typeclass for a particular type. That is, for example,
the List type can have many instances for different typeclasses, but
it can’t define more than one instance for the Functor typeclass. Of
course, besides List, other types can implement instances of the
Functor typeclass as well. An instance, in other words, is what
establishes the relationship between a typeclass and a type
belonging to it.

Next comes the implementation of fmap, which looks exactly like


the map function for List we implemented a while ago. Whereas in
the typeclass definition, where we said class Functor f where …, we
specified the type of fmap without giving an implementation for it,
here the opposite is happening: We are only specifying its
implementation. Why? Well, according our instance head, that is,
that which appears to the right of the name of the typeclass Functor
in our instance clause, we can see that List has taken the place of the
f placeholder we had in the typeclass. This implies that, within this
particular instance, all mentions of f will be replaced by List.
Concretly, the fmap :: (a → b) → f a → f b described in the
typeclass definition, will have the type (a → b) → List a → List b, so
there’s no need to repeat this obvious truth here.
37. Parametricity
Whatever do we gain from writing typeclasses and instances and
methods instead of just plain old functions? Well, aren’t we
forgetting why we are here at all? We had a map function that
misbehaved, always returning an empty list, and we wanted to
avoid ever having that. Getting there will take some time, but let’s
take a look at something else we have accidentally accomplished
meanwhile.

add_ones :: Functor f => f Natural -> f Natural


add_ones = fmap (add 1)

Here we are defining a new function, add_ones, that given any f that
satisfies the Functor constraint —that is, an f that implements a
Functor instance— will return a transformed f that increases each
Natural number contained in it by one. Any f, that’s what’s
important to notice. This f can be a List, it could be Haskell’s own
list with that weird square brackets syntax, or it could even be
something completely different. Perhaps a bit surprisingly, it could
be Maybe. Yes! Why not? After all, a value of type Maybe Natural
could potentially contain a Natural number that we could increase
by one. In fact, we said before that Maybe is essentially a possibly
empty one element list, so it shouldn’t surprise us that these types
can achieve similar things. Let’s see how the implementation of the
Functor typeclass for Maybe looks like.
instance Functor Maybe where
fmap = \g ya ->
case ya of
Nothing -> Nothing
Just a -> Just (g a)

The implementation of fmap is easier this time because, if any, we


only have one value inside Maybe to which we could apply the
function g. We don’t need to worry about recursing into the
structure to find more values, which greatly simplifies our
implementation. Other than that, things are the same as in the List
instance: If we apply fmap to Nothing we simply return Nothing
because there is no value to which we can apply g, and if we apply
fmap to Just something, then we return a new Just where its payload
has been transformed by g.

Naturally, add_ones [1, 2, 3], say, will result in [2, 3, 4] as


expected. Well, to be fair it won’t because we haven’t yet
implemented the Functor instance for Haskell’s weirdly syntaxed
list, so the type-checker will complain that we are trying to use fmap
with something that doesn’t implement a Functor instance. But let’s
imagine we have, a bit of wishful thinking doesn’t hurt. We will
implement that instance soon enough. Anyway, we could try
add_ones (Cons 1 (Cons 2 (Cons 3 Nil))) instead, which is
conceptually the same, and we would get Cons 2 (Cons 3 (Cons 4
Nil)) as expected. But we can now say add_ones (Just 5) as well,
which the type-checker will gladly accept and will result in Just 6.
Saying add_ones Nothing, of course, results in Nothing.

It’s important to highlight that we don’t need to explicitly tell


functions like add_ones which instance of a particular typeclass for a
particular type they need to use. As we said, we can at most have
one such instance, so the compiler will automatically select it for us.

What we have achieved is called polymorphism, a word meaning


many shapes in Greek. And sure enough, we had many shapes here.
add_ones, in its type Functor f ⇒ f Natural → f Natural, doesn’t say
anything concrete about the shape —that is, the type of f— it will
work with, but rather, it says that it can work with any shape so
long as there is a Functor instance for it and contains Natural
numbers somehow. This is great, because now add_ones doesn’t
know any specific details about f, thus it can’t do silly things such
as returning an empty list or a list shorter than the one given as
input. Well, actually, we can’t even say list since that’s already
much more specific than saying just Functor. Try it. Try
implementing a broken add_ones that changes the shape of f. We
can’t do that. We only know that f can be mapped over, we don’t
know what it looks like, so we can’t alter its shape. Of course, we
could still implement a “broken” add_ones that instead of adding one
to each element, adds two. We would be able to do that because
add_ones is not entirely polymorphic; it is polymorphic on f, but it
also knows that it deals with Natural numbers, so it can modify
them in any way Natural numbers can be modified. Is this too much
knowledge? Perhaps, but we need to learn to find the balance
between reason and ridicule. Sometimes, simply naming the
function after what it does is a sensible compromise.

Now, not all polymorphic functions are like add_ones, requiring


that a particular unknown parameter be a Functor or something. In
fact, most of the functions we have encountered so far in this book
are polymorphic, even though we only learned the word just now.
Let’s take a look at the type of our beautiful identity function once
again.
id :: x -> x

What the type of id is saying is that x could be anything. No matter


to what shape we apply id, it will type-check and work. It is a
polymorphic function indeed. The only difference here is that we
are not asking x to satisfy a particular set of features through a
typeclass instance, but that is alright, we know id simply returns its
input untouched, so it makes sense that there are no further
requirements on x. Even constructors such as Just, with its type x →
Maybe x are polymorphic. Just says that given an x, any x, it will
type-check and return a Maybe x.

Our type of polymorphism, no pun intended, is called parametric


polymorphism. A reasonable name considering these many shapes,
even though unknown, still show up as type parameters in the
types of our functions and constructors allowing us to reason about
how we could potentially deal with the unknown. This power we
gain by abandoning the terran understanding of what a type is,
instead focusing on what properties a type has and what it can do,
is called parametricity, and it is such a beautiful and necessary
power that in this book we learned about it before learning
anything else, back when we first encountered id, even if it is only
now that we know its name. Parametricity tells us that no matter
what the unknown types might be in our polymorphic function,
the behavior of the function will always be the same. add_ones adds
one to all the elements of any Functor, whereas id returns whatever
is given to it, and this is true for all types we could choose to use
with them.
38. Law
So, by relying on fmap we can’t get add_ones to misbehave regarding
its unknown type parameter f. However, nothing prevents us from
getting the implementation of fmap itself wrong. Think about it,
just like we gave a broken implementation of map once, we could
give a broken one for fmap.

instance Functor Maybe where


fmap = \_ _ -> Nothing

In this instance, the type of the fmap method is (a → b) → Maybe a →


Maybe b. We know this because it is what we get if we replace f with
Maybe in fmap's type, as required by the Functor typeclass definition,
which we recall here:

class Functor f where


fmap :: (a -> b) -> f a -> f b

Our allegedly broken fmap fits this type perfectly, so what is the
problem? Is there a problem at all? Well, we the authors of this
mess can see that fmap will ignore its inputs and always return
Nothing, so yes, there is a problem. How is this possible? Weren’t
typeclasses supposed to save us from this pain? Well, it is a bit more
complicated because the type-checker can’t help us this time.

Typeclasses are usually accompanied by laws by which their


instances are expected to abide. Otherwise, they could be sentenced
to prison. Just kidding. The laws in question are different from
those of civilization, yet they serve a similar purpose in that they
clarify the expectations of what should happen in a given scenario.
Unfortunately, these laws cannot be expressed in the types, even
though we would very much love doing that. They are, essentially,
the rules that an imperfect type system let fall through its cracks.
Laws, like types, simply prevent us from writing nonsense that
could lead to unexpected behavior.

What happened in our broken fmap is that while it met the


expectations of the type system, it failed to satisfy the Functor laws.
This is, unfortunately, understandable, considering these laws
haven’t appeared anywhere in our source code yet. Let’s see what
these laws are, and later on we will figure out where to write them
down.

The first Functor law, which we call the functor identity law says
that mapping the identity function id over some Functor x should
return that same x unmodified:

fmap id x == x

This should be rather unsurprising. And dull, also dull. That’s OK.
In other words, we are saying that applying fmap id to something
should have the same innocuous effect as applying id to it.

fmap id x == id x

Does our broken Functor instance for Maybe satisfy this law? Let’s
see. If we try, for example, fmap id Nothing, where Nothing of type
Maybe Natural takes the place of the x we mentioned above, then the
result is expected to be Nothing. That is, the same x again. Great, it
works, fmap id Nothing is indeed Nothing. However, this law must be
satisfied for all choices of x, not just Nothing. For example, x could
be Just 5. Does fmap id (Just 5) return Just 5? No, it does not. Our
broken fmap implementation within the Functor instance for Maybe
simply ignores its input and returns Nothing every time. Among
other things, this behaviour violates the functor identity law. This
proves that the fmap implementation we gave is indeed incorrect,
thus we can’t say Maybe is a Functor if such is the best
implementation of fmap we can come up with. Luckily, we already
know it’s possible to come up with a correct implementation of
fmap for Maybe; we did it in the last chapter.

The second functor law is a bit more challenging, but we need to


brush up our Haskell in order to approach it.
39. Composition
Somehow we made it this far without having talked about
composition, which is a bit funny considering how composition is
what makes our efforts in paying attention to being able to reason
about our code worthwhile.

Composition, as the name hints, is about bringing things together


in order to create something new and different wherein traits of
those original things are still present. In programming, in Haskell,
we compose all day long. Above everything else, that’s what we do.
A program, essentially, is just one big composition of smaller
programs. But composition takes many shapes, and we can’t tackle
all those shapes at once, so let’s focus today on function composition.

Imagine we want to multiply a number by ten and then add one to


it. For example, given 2 we would obtain 21. That is, (2 * 10) + 1.

foo :: Natural -> Natural


foo = \x -> (x * 10) + 1

The idea of function composition is that rather than introducing a


new function that explicitly does two things, like foo which is
explicitly multiplying by ten and then adding one to the result here,
we can say that foo is the composition of multiplying by ten and
adding one.

foo :: Natural -> Natural


foo = compose add_one multiply_by_ten

Western traditions will encourage us to wonder whether the


parameters in this function application are out of order. An
irrational inertia will want us to write compose multiply_by_ten
add_one instead, seeing how we are expecting to multiply_by_ten first,
add_one second, and how we have only ever learned to read from left
to right. But if we search deep inside, we’ll find we can
acknowledge that there’s nothing intrinsically natural about left to
right reading, just like how there’s nothing wrong in writing upside
down. We embrace these differences and we are at peace. Today,
for practical reasons that will become apparent later on, from right
to left we will write. When we say compose add_one multiply_by_ten,
it is multiply_by_ten who comes first, and that is fine.

So let’s first get the implementations of multiply_by_ten and add_one


out of the way. They are not important, function composition
works the same for any two functions that fit the expected types,
but we need them for this one example.

multiply_by_ten :: Natural -> Natural


multiply_by_ten = \x -> x * 10

add_one :: Natural -> Natural


add_one = \x -> x + 1

Can we guess what compose is? Well, actually, we don’t need to


guess. We have all the information available to understand what
compose actually is. Let’s first look at its type. In our foo example we
are applying compose to two parameters in order to obtain a value of
type Natural → Natural. Let’s see how this partial knowledge looks in
the type of compose.

compose :: _ -> _ -> Natural -> Natural

We can also write it like _ → _ → (Natural → Natural) if we want to


highlight the fact that we are “returning a function”. Both the extra
parentheses and saying “returning a function” would be redundant
though. We learned this before. The parentheses, implicitly, are
already there, and we always “return a function” whenever we
partially apply the function that returns it. Sometimes, however,
these visual aids help us understand the intended purpose of our
programs.

We still have two blanks there to fill where we wrote _. But they are
quite easy to fill, aren’t they? We are already applying compose to
two functions multiply_by_ten and add_one, so we simply write
down their types there.

compose
:: (Natural -> Natural)
-> (Natural -> Natural)
-> (Natural -> Natural)

Our type started getting a bit long, so we split it across multiple


lines. Notice how we put parentheses around the parameters we
just added. If we hadn’t, then we would have ended up with
something else:

compose
:: Natural
-> Natural
-> Natural
-> Natural
-> Natural
-> Natural

That is, rather than compose being a higher-order function that


expects two functions as input and returns yet another function as
output, it would have been a function taking five Natural numbers
as input and returning yet another Natural as output. The
parentheses are very important here.

compose
:: (Natural -> Natural)
-> (Natural -> Natural)
-> (Natural -> Natural)

What about compose's implementation? Well, we know we want to


achieve the same thing as our foo = \x → (x * 10) + 1 did, and we
know that we are applying compose to add_one and multiply_by_ten
which are, essentially, the things we want to do to our input one
after the other. So why don’t we do just that ?

compose
:: (Natural -> Natural)
-> (Natural -> Natural)
-> (Natural -> Natural)
compose = \g f x -> g (f x)

If we find it shocking to see three parameters in this lambda


expression —g, f and x— while only two of them seem to be
mentioned in the types, just remember that the parentheses around
that last Natural → Natural are optional. We could have written it
without the parentheses instead, which would have been arguably
easier on the eyes:
compose
:: (Natural -> Natural)
-> (Natural -> Natural)
-> Natural
-> Natural
compose = \g f x -> g (f x)

This is compose. We can clearly see in \g f x → … that this function


takes three input parameters, and we can see said three parameters
in the types, each on its own line. Now, if we beta-reduce f and g
—that is, if we replace them with the actual values they take in
compose add_one multiply_by_ten— then we end up with \x →
add_one (multiply_by_ten x). And isn’t it true that this is the same as
our original foo, which said \x → (x * 10) + 1? Yes, yes it is.
40. Polymorphic composition
Now, nothing about our compose says that this function is about
composing functions. In fact, here’s a valid implementation of
compose insofar as its type is concerned:

compose
:: (Natural -> Natural)
-> (Natural -> Natural)
-> Natural
-> Natural
compose = \_ _ _ -> 8

Sure, why not? We accept three parameters as input, and then


simply return 8. The type-checker allows this and our program
compiles just fine. However, hopefully we can agree that this is silly
and unintended. We’ve come here many times, we know what the
issue is: We know too much. All those Naturals in the type of
compose are just a liability, we must get rid of them.

All our working compose ever does in its implementation is apply


some functions. So, since we are not making use of any feature
specific to Natural numbers in our correct implementation of
compose, we might as well replace all those Naturals with some type
parameter x.

compose :: (x -> x) -> (x -> x) -> x -> x

With this change we don’t know what x is anymore, so we can’t


create an arbitrary value of type x to return from compose. Or can
we?
compose :: (x -> x) -> (x -> x) -> x -> x
compose = \_ _ a -> a

While it is true that in this new and broken version of compose we


are not arbitrarily creating a value of type x, we are still returning
the wrong x value. This function simply reuses some of input as its
output, unmodified. Seeing as how a value of type x is expected,
and how in a we have a value of such type already, we might as well
return it. But how can it be that while we know nothing about what
x is, we are still able to come up with the wrong x? Have we lost?
No, we haven’t.

A responsible programmer, like a responsible citizen, must call out


and replace broken rules. And the rules here, the types, are broken.
We must constantly try to subvert our own types if we expect our
programs to be reliable and stand up to scrutiny.

The problem here is that nowhere in the type of compose are we


enforcing that compose g f a must apply both f and g in a particular
order. But we can solve that by relying on the reasoning power
gifted to us by parametric polymorphism. Let’s look, finally, at the
correct type and implementation of compose.

compose :: (b -> c) -> (a -> b) -> a -> c


compose = \g f a -> g (f a)

This type is saying that compose eventually returns a c. It also says


that among its input parameters, there is a function b → c which
given a b allows us to obtain a c. And where do we obtain that b?
Well, there is yet another function among the input parameters, a →
b, that will give us a b if we provide it with an a, an a just like the one
that is provided as one of the input parameters to compose. So if we
use that a to obtain a b, then we could use that b to obtain the c that
compose is expected to return. Now, the type of compose not only
forces its implementation to use both f and g, but it also mandates
that f, not g, be applied to a first. Moreover, while before we had all
types be Natural or a same mystery x, we can now have a, b and c be
different types. For example, if we had a function f of type Natural
→ Season, and a function g of type Season → String, then compose g f
would have type Natural → String.
41. Second functor law
Now that we know about function composition, we can learn the
second functor law.

fmap (compose g f) x == fmap g (fmap f x)

As a reminder, we are not writing any Haskell definition here, we


are just stating some expected equalities using a familiar Haskell
notation for ourselves. This law says that whether we compose two
functions f and g together before mapping their composition over
some Functor, or we map f over our Functor and afterwards we map
g over the result, the outcome should be exactly the same.

If we drop the x from the equality above, we can write both sides of
the equality in an arguably clearer pointfree style.

fmap (compose g f) == compose (fmap g) (fmap f)

This law guarantees that we can map over a functor as often as we


want, without worrying that doing so might affect the output of
our program somehow.

Did our broken Functor instance for Maybe, the one that always
returned Nothing, violate this law? Not really. Both fmap (compose g
f) and compose (fmap g) (fmap f) would return the same Nothing.
Good thing we had the other law, the functor identity law, to
prevent that nonsense from happening.
42. Comments
So where do we write these laws? Well, Haskell doesn’t provide us
with mechanisms for laying down laws for typeclasses in such a way
that instances of that typeclass are automatically checked for
compliance. Wouldn’t that be nice, though? No, in Haskell we are
unfortunately on our own on this matter, and at best we can write a
comment about it.

Comments have nothing to do with these laws we’ve been talking


about, actually. Laws are just an excuse for us to talk about
comments. You are right to feel tricked into this matter. Comments
are simply arbitrary words we can write in our source code which
are completely ignored by the compiler. Comments, intended for
humans to read, are where we can clarify the purpose, behavior or
intention of something. We can add comments to functions,
typeclasses, etc. Let’s, for example, add some comments to our add
function.

-- This function performs the addition


-- of its two input parameters.
add :: Natural -> Natural -> Natural
add = \x y -> x + y -- Here is another comment!

Comments start with -- and extend to the end of the line.


Whatever comes after -- is simply ignored by the compiler. We can
use this space to write anything we deem important enough, so that
whoever reads this code in the future can more easily understand
what is going on without having to actually read the code.

So, lacking a better tool, we resort to comments in order to lay


down the law. We can imagine the Functor typeclass saying
something like this:

-- Functor instances are expected


-- to satisfy the following two laws:
--
-- 1. Identity law
--
-- fmap id == id
--
-- 2. Composition law
--
-- compose (fmap g) (fmap f) == fmap (compose g f)

class Functor f where


fmap :: (a -> b) -> f a -> f b

We can’t prove that all Functor instances abide by these laws, but
we can prove that this is true sometimes, on a case by case basis. So
far, we have been doing this with pen and paper, writing down in
English the reasons why these laws hold or not. Is this satisfactory?
Of course not, but here we are. Is this an accident? Is this Haskell
abandoning us? Kind of. What’s happening is that the type of fmap
is not rich enough to guarantee the semantics we expect when using
it, so we need to change fmap's type to be more descriptive. Doing
this with Haskell’s type system, however, is not really quite
possible. Or at least, it’s not at all practical. Like the language
without coproducts, like the language with just the string, here we
find ourselves longing for something we do not have, without
which we are forced to acknowledge a problem that could arise at
runtime unless we manually prove that these laws are indeed
respected. In the future we will see how we can write better proofs
that the computer can check for us, but for now let’s just embrace
this handicap and move on.

Anyway, laws or not, comments are good. We will continue


learning how to write great comments throughout this book. And
yes, we could arguably say more in our comments for Functor, we
could say that “a Functor is a thing that can be mapped over” or
something along those lines, but we don’t want to jump ahead and
accidentally write down a tautological or imprecise definition, so
let’s not do that just yet.
43. Fixity
We talk about functions, we discuss how they are a fundamental
unit of computation, yet we see things like 2 * 3 computing some
number without an obvious function application going on. Well, it
turns out that there is a function application going on: * is the
function, it’s just that instead of appearing before its parameters as
* 2 3, it appears in between them. We say that * is an infix function.
And, as every other function out there, * has a type. For now, let’s
say the type is Natural → Natural → Natural.

But could we actually write * 2 3 if we wanted to do so? Well, not


exactly, but we could sprinkle some extra parentheses, write (*) 2 3,
and it would work. Whenever a function like * is expected to be in
an infix position —that is, in between its parameters— we need to
surround it with parentheses if we want to use it as a “normal”
function preceding its inputs. When a function is used in this way,
preceding its inputs as we’ve been doing for a long time, we say it is
used in a prefix position. We don’t say it often, though, since prefix
it is the fixity we get by default when we define a new function or
constructor, so we just assume functions to be intended to be used
in prefix position.

How do we define an infix function? Let’s try defining * with its


usual behavior as multiplication of Natural numbers. Of course, *
already comes out of the box with Haskell, but we’ll reimplement it
here just as an exercise.
(*) :: Natural -> Natural -> Natural
(*) = \x y ->
case y of
0 -> 0
_ -> x + x * (y - 1)

infixl 7 *

The function definition shouldn’t be surprising. This is just a


normal function which happens to be called *. The parentheses are
there because, otherwise, when the Haskell compiler sees a strange
name like * made out of symbols expected to be part of an infix
function name rather than letters, it refuses to parse these lines of
code. There are some very boring rules about what constitutes a
“normal name” and what is weird enough to require an extra pair
of parentheses, but we won’t go into details about that.

The implementation of the function is recursive, inductively


recursive. Essentially, we are adding together as many xs as y
requires. Each time we add an x, we decrease y by one before
recursively calling *, which will once again add an x, etc. Eventually,
we reach the base case of y being 0 and we stop by returning 0. For
example, 5 * 0 becomes 0, 5 * 1 becomes 5 + 0, and 5 * 2 becomes 5
+ 5 + 0.

Somewhere in our code we wrote x + x * (y - 1) and, implicitly,


we knew we meant x + (x * (y - 1)). That is, there are a pair of
implicit parentheses around our multiplication that make it happen
before the addition. If the parentheses were around the addition, as
in (x + x) * (y - 1), then the result of this function would be
different. We can learn where any implicit parentheses go by
understanding the fixity of our infix functions. In our example, in
the line where we say infixl 7 *, we are saying that *, when used as
an infix function, has a precedence of 7 and “associates to the left”.
This precedence of 7 is what forces the implicit parentheses to be
where they are whenever we have, say, both + and * in the same
expression. If we were to look at the fixity declaration for +, we
would find it says infixl 6 +. And 7 being a bigger number than 6 is
what forces the parentheses to surround a multiplication rather
than an addition when * and + are next to each other. 7 and 6 have
no special meaning on their own, it just happens that one of these
numbers is bigger than the other one when we consider them
alongside each other, and that’s enough for our needs.

The other fixity property about * “associating to the left” dictates


where the implicit parentheses go when we have multiple
occurrences of infix functions with the same precedence,
something like 2 * 3 * 4. In the case of multiplication, it doesn’t
really matter whether we say 2 * (3 * 4) or (2 * 3) * 4; the result is
the same in both cases. We say that multiplication is associative,
meaning that no matter where we put our parentheses, the final
result is always the same. However, not all functions are associative,
so Haskell asks us to declare this property nonetheless. But where
did we say * associates to the left? We did so when we wrote infixl,
where that trailing l stands for left. Of course, we also have infixr
for whenever we need something to associate to the right. It’s
important to keep in mind that whether we say infixl or infixr
doesn’t affect the fact that the parameter to the left of our infix
function always becomes the first parameter to our function, and
the one to the right becomes the second one. That is, in 2 * 3, 2
becomes the x in (*) = \x y → …, and 3 becomes the y.

Isn’t this boring and noisy? Isn’t it frustrating to try and guess
where the implicit parentheses may or may not be? Yes, of course it
is. This is why we try to avoid infix functions, at times called infix
operators, as much as possible. To make it easier for us, and to make
it easier for our colleagues who will have to read our code
tomorrow. Yet, arithmetic operators such as + and * are so
ubiquitous that we need to understand this.
44. List constructors
Before we talked about how we could use the : constructor to cons
an element onto the linked lists that come with Haskell and have
that square bracket syntax. We said we could use something like 3 :
[] to prepend 3 to the empty list. It should be apparent now that
what we were saying was that : is an infix constructor. If we
wanted to use : in prefix position, we could do it by simply adding
those extra parentheses we talked about before. For example, (:) 3
[] is the same as 3 : [], except uglier.

Now, the type of the : infix constructor, comparable to the type of


Cons, is x → [x] → [x]. In other words, if we put an x to the left of the
: symbol and an [x] to its right, we’ll get back an [x] as output. And
if we wanted, we could use this newly obtained [x] again in yet
another application of :. That is, we can say 3 : [] which gives us a
[Natural], and we use this 3 : [] further to say 2 : 3 : [], which
gives us yet another [Natural].

Can we tell from its usage whether the : infix constructor associates
to the left or to the right? Where would we put our implicit
parentheses if we wanted to? (2 : 3) : [] wouldn’t type-check,
because while one of our : has a perfectly acceptable [] as its second
parameter, it also has 2 : 3 as its first parameter, which doesn’t
make any sense. Remember, : needs the value of a list element as its
first parameter, and a list as its second argument. 3, however, is no
list. Thus, we can say with confidence that : doesn’t associate to the
left, otherwise these parentheses wouldn’t have prevented the
expression from type-checking. On the other hand, putting
parentheses to the right as in 2 : (3 : []) works perfectly: Both :
have a Natural number to the left and a [Natural] to its right. In
other words, : associates to the right, and now we know why [1, 2,
3], 1 : 2 : 3 : [], 1 : 2 : [3] and 1 : [2, 3] all mean the same.
45. Abstraction
Some things, like natural numbers, we can count with our fingers.
Other things, like temperatures, we can feel on our skin. These are
very concrete things, things that require almost no effort from us in
order to acknowledge their presence and meaning in this world.
But not all things are this way. Some things, like recursion, functors
or love, abandon their corporeal identity in order to become
abstractions. What is a functor? It is something that has a particular
behavior. What is recursion? “What is recursion?” indeed. Can we
touch love? Can we draw a functor in the sand? No. If we are going
to gain a deeper understanding of what we’ve seen so far, of what’s
to come, then we need to abandon our corporeal expectations and
become thought. We call these things, forgetful of their actual
identities, abstractions.

What is a functor, anyway? We saw how Lists are functors. And it


was easy, because applying a function a → b to all the as in a
container full of them is a rather straightforward thing to do: The as
are in there, we just do it. We also saw how Maybes are functors. And
it was easy, because Maybes are essentially one-element containers
themselves, so it wasn’t surprising at all that what was true for Lists
was true for Maybe as well. So functors are containers? Why didn’t
they just call them that? Sure, a container is some kind of
abstraction, if you will. And containers are frequently functors too.
Rather than talking about Lists, Maybes, drawers or cupboards, we
forget the specifics, talk about containers as the things sharing the
particular property of having other things inside, and thus avoid
getting into the details of what concrete type of container we are
dealing with. A knowledge, we recall, that has bitten us quite hard
in the past. But is this all there is to functors? Containers? How
disappointing, how terran.
In Haskell, mathematics in disguise, our abstractions, the beautiful
ones, seldom talk about things themselves. They talk instead of how
things relate to each other. We see this in the quintessential identity
function, which talks not about the particulars of a thing, but
about the relationship of a thing with itself. Or functors, which are
defined not as things having container-like features, but as the
relationship of a thing with the types and laws it is expected to
fulfill. No, most functors are not containers at all.
46. Functor f
Functions are everywhere. They are the foundation of what’s
computable, and we seem to be defining everything we do on top
of them. This makes sense considering how abstract functions are,
and how we are dealing with programs expected to be computed at
some point after all. But while functions are this fundamental in
programming, they are not so in mathematics as a whole, where our
knowledge comes from. Of course, they are terribly important
there as well, but what we mean is that even without talking
concretely about functions, we can still say things about their
expected behavior, and about what our programs should compute.
That is, we have even more abstract ways of talking about functions
than functions themselves, and functors are one such way. Yes.
Functions, these very container-unlike things, are functors as well,
and we will now start a journey to understand how. First, let’s recall
what the Functor typeclass looks like.

instance Functor f where


fmap :: (a -> b) -> f a -> f b

As long as we can find an f for which an instance of the Functor


typeclass can be implemented while respecting the functor laws,
then we can say that the chosen f is a functor. In other words, if we
are stating that functions are indeed functors, then we must be able
to write a Functor instance where functions, somehow, are that f.
How, though? It’s not obvious, is it?
47. The right
It is important to remember that in Functor f, the f is expected to
be a type constructor, not a type. That is, we pick things such as Maybe
or List to be f, not Maybe Natural or List String. Think about it.
What type would fmap take if f was Maybe Natural?

fmap :: (a -> b) -> Maybe Natural a -> Maybe Natural b

That doesn’t make any sense. What is Maybe Natural a if not


nonsense that the type-checker will reject? No, f must be a type
constructor which, when applied to some arbitrary a or b, becomes
a full blown type suitable for hosting an expression at the term
level. If we pick f to be Maybe, not Maybe Natural, then we end up
with a sensible type for fmap.

fmap :: (a -> b) -> Maybe a -> Maybe b

Yet, in Maybe Natural a, an impossible type, we see a striking


resemblance to Either Natural a, a perfectly acceptable one. This
suggests that Either Natural —or Either whatever, for that matter—
could be a suitable f.

fmap :: (a -> b) -> Either x a -> Either x b

Indeed, a perfectly acceptable type. How exciting! Quick, let’s


make a Functor.
instance Functor (Either x) where
fmap = \g e ->
case e of
Left x -> Left x
Right a -> Right (g a)

Aesthetics aside, this is the only possible behavior for the fmap
method in this instance. Much like how parametricity forced the
implementation of id and compose to achieve what they do, here it is
forcing fmap to have this behavior, the only one that type-checks.
Try to implement it differently; it won’t work.

According to fmap's type (a → b) → Either x a → Either x b, no


changes are ever made on x, the payload of the Left constructor, so
we leave Left x untouched if we see one. On the Right we are
responsible for actually evolving this datatype, somehow producing
a b payload as output. And we do so in the only way we possibly
can: By applying g, a function of type a → b, to the a value on the
Right constructor in order to obtain a b. It’s important to be aware
that when we say Left x → Left x, the type of the first Left x is the
same as the e we are scrutinizing —that is, Either x a— but the type
of the expression we are returning as output, to the right of the
arrow →, is Either x b, as mandated by the type of fmap. This is
similar to how at some point we said Nothing → Nothing in the
Functor instance for Maybe, yet those two Nothings had different
types.

So we can say out loud that given a value of type Either a b as


input, fmap modifies the b somehow, if any, possibly changing its
type, but leaves the a untouched. So, for example, fmap add_one
(Left 2) results in the same Left 2, but fmap add_one (Right 2)
results in Right 3.
48. The left
In other words, we can’t ever use fmap to modify the payload on the
Left constructor of an Either. Or can we? This seems to be a rather
arbitrary choice. If Functors are supposedly there to allow us to map
a function over all the elements inside our chosen f, why are we
skipping half of them? Why the Right and not the Left? Well, let’s
look at the types again.

fmap :: (a -> b) -> Either x a -> Either x b

This is what we have. It says in the tin that the Left never changes.
But, could we have it the other way around? Tackle the Left
instead?

mapLeft :: (a -> b) -> Either a x -> Either b x


mapLeft = \g e ->
case e of
Left a -> Left (g a)
Right x -> Right x

Nothing wrong with that. It works. It type-checks. The problem,


however, is that while this is a fine function worthy of the name
mapLeft, it couldn’t possibly be the implementation of the fmap
method of the Functor typeclass. Why? Well, what would f be?

instance Functor ‽ where …

We used Either x before as our f. A partially applied Either, a type


constructor whose last parameter, the type of the Right payload,
hasn’t been provided yet. Now, however, we would need to come
up with something that leaves out the type of the Left parameter.

instance Functor (Either ‽ x) where …

That, however, is not possible. We can workaround it, sure. In fact,


if you dwell on it for a bit, you yourself may come up with a
workaround. We have all the tools already. However, we are in no
hurry to solve this, so we’ll leave it for later. Our thirst is for
understanding, not for a sense of accomplishment. Let’s
understand what is going on with that mystery f instead, and why
we seem to be able to use fmap on the Right but not on the Left.
49. Kinds
Just like how expressions are of a particular type, and how we use
those types to tell apart some expressions from others, types
themselves also have their own “types”, if you will, which we use
for telling them apart from each other. They are called kinds, and
much like types themselves, they exist only at compile-time and are
there only for the type-checker —or rather, kind-checker— to see.
And what types would we like to tell apart? Well, types such as
Natural and String surely convey different ideas. Perhaps them? Not
quite.

Natural and String certainly are different, but aren’t all types
different? That’s why we have types at all, because we want to tell
apart expressions that convey different concepts by tagging them
with types that the compiler will reject if different than expected.
Natural and String are different in the same way the numbers 2 and
7 are: If we are planning to add 2 to some number, but we
accidentally add 7, say, the result will be wrong. But the fact that we
were able to add 7, rather than 2, says something about how these
two things are not that different after all. They are both, indeed,
numbers. With kinds, we have a similar situation. To understand
this, let’s look at our identity function once again.

id :: x -> x

Our beautiful id says that given an x as input, any x we can come up


with, it will return it as output. Any x. We try to give it 3, a Natural
number, and it works. We try with Nothing, a value, say, of type
Maybe String, and it works. We even try to use id itself as the input, a
value of type x → x, and it works as well. Indeed, id works with
values of any type. But that’s the thing. Just like how 2, 7 and 12 are
all numbers, and we can readily, accidentally or not, use one where
the other was expected, any type can appear wherever a type is
expected. This says something. This says that types such as Natural,
String or a → a, even though different from each other, are all still
types. And why does this obvious thing matter? Because by being
able to precisely identify what a type is, we can safely say that
anything that exists at the type-level but is not a type, anything that
the type-checker can see but can’t call a type, must definitely be
something else. Can we think of one such thing?
50. Kind notation
Type constructors, they aren’t types. Can we, for example, apply id
to a value of type Maybe? Sorry, trick question. No, we can’t even
come up with a value of such type, because neither Maybe nor any
other type constructor is a type. It says so in their name, they
construct types. Only types can have corresponding values at the
term-level. So what is a type constructor, anyway? Let’s reason
about this using kinds. First, let’s see what’s the kind of a “normal”
type like Natural.

Natural :: Type

When writing down kinds, we use the symbol :: to state that the
thing to its left is a type, and the thing to the right its kind. Here we
are saying that the type Natural has kind Type. There are a couple of
confusing things about this. First, we are reusing the same symbol
:: that we used for stating that some expression has a particular
type, like in 2 :: Natural. However, if we consider that this is
something that, out loud, we read as “2 has type Natural”, and that
in turn we read Natural :: Type as “Natural has kind Type”, which is
true, then we should be at ease. This, actually, is valid Haskell code:

2 :: (Natural :: Type)

We need those parentheses because ::, by default, associates to the


left. So without the parentheses we would end up with a type-
checker trying to understand (2 :: Natural) :: Type, which doesn’t
make sense because 2 :: Natural is not a type, it is an expression to
which we are explicitly giving the type Natural. And we just said
that when specifying the kind of a type we need to write the type to
the left of the symbol ::, and the kind to its right. So, the type-
checker rejects this. By explicitly putting the parenthesis to the
right, as we did, we end up with the idea that “2 has type Natural,
and Natural has kind Type”, an idea that the type-checker will gladly
accept.

The second thing that might be a bit confusing about this notation
is that we are saying that Natural :: Type means “Natural has kind
Type”. That is, we are seeing the word “type” appear in the place we
supposedly talk about kinds. But this makes sense, types have kind
Type indeed. Type is just a name somebody chose for this kind of
things. Other kinds of things are named differently.

So let’s just try and embrace this notation. The symbol :: is used
both for conveying the type and the kind of something, and
whenever we see Type, we must remember we are dealing with a
kind, not a type.
51. Type constructors
We can tell types apart from type constructors by looking at their
kinds. While a type like Natural has kind Type, a type constructor
generally has kind Type → Type.

If Type were a type —it isn’t, it is a kind— and we were to find a


function of type Type → Type, then, without hesitation, we would
say that this was a function that takes an expression of type Type as
input and returns an expression of type Type as output. Well, that’s
exactly what’s happening with type constructors, except involving
types and kinds, rather than expressions and types. Let’s look at
Maybe, for example. Maybe is a type constructor of kind Type → Type.
This implies that given a type of kind Type as input, we get a type of
kind Type as output. And this is exactly what happens. Consider
Natural, for example. Natural is a type, so it has kind Type. If we
apply the Maybe type constructor of kind Type → Type to Natural, then
we end up with Maybe Natural of kind Type.

Of course, like functions, type constructors can also take multiple


parameters as input. Well, we know that in truth functions only
ever take one parameter in Haskell, but let’s pretend they take
many, which for our practical intents and purposes is true.
Anyway, type constructors can also take more than one parameter
as input. Think of Either, for example. What is the kind of Either, a
type constructor that needs to be applied to two parameters in order
to become a type? It is Type → Type → Type, of course. Applying
Either to two Types, say Natural and String, gives us Either Natural
String, a Type. What happens if we partially apply Either, though?
That is, if we only give it the first of the two input Types? Can we do
that? Sure we can, we did it earlier when we were toying with
instance Functor (Either x), remember? That Either x is a partially
applied Either. We don’t know what x is, sure, but it doesn’t matter.
We know that any type —that is, any Type— can occupy x's place.
And what happens after we apply a type constructor of kind Type →
Type → Type to something of kind Type? We end up with a type
constructor of kind Type → Type, much like how applying a value of
type a to a function of type a → b → c leaves us with yet another
function of type b → c.

So there we were, defining the Functor instance for Either x, a type


constructor with kind Type → Type. This suggests that the mystery fs
for which we can actually say instance Functor f should perhaps
always be of kind Type → Type. Should they, though? Well, we were
able to define Functor instances for List and Maybe as well, both type-
constructors of kind Type → Type. Promising results. However, the
fact that we were able to do this a couple of times doesn’t imply
that it must always be this way. So let’s go back to the source, to the
typeclass, to understand the truth.

class Functor f where


fmap :: (a -> b) -> f a -> f b

We see f show up both as an input parameter to the fmap method in


f a, and as the method’s output in f b. We will analyze those use
cases to determine what the kind of f is. What do f a and f b have
in common? They could be different values, sure, and they each
play a different role in fmap, but they are also both expressions.
They have that in common. And expressions, we know, have types.
And by “types” we mean things of kind Type, of course. So f a and f
b must themselves be Types. But also, both a and b show up as
standalone types in a → b as well, which implies that a and b are also
Types. But if f a and f b are Types, and if a and b are themselves Types
as well, then f, which is being applied to each of a and b with the
expectation of getting yet another Type in return, must necessarily
have kind Type → Type. In other words, the f in Functor f must
always have kind Type → Type. In fact, while not necessary, if we
wanted to be explicit about this, we could have mentioned the kind
of f in the typeclass definition of Functor. This can sometimes be
useful to readers of our code.

class Functor (f :: Type -> Type) where


fmap :: (a -> b) -> f a -> f b

So now we know why giving a Functor instance for Natural or Maybe


String doesn’t work. It’s because they have kind Type, not Type →
Type, so the type-checker readily rejects them. A Functor instance for
Either doesn’t work either because Either has kind Type → Type →
Type, different than the expected Type → Type.

And from here we can see why we can’t use fmap to work on the
Left side of the Either: It is because if we realize that Either x, a
type-constructor with kind Type → Type as expected by the Functor
typeclass, must be the f in our Functor instance, then that f will
continue to be Either x anywhere it appears inside the Functor
instance, which includes the fmap method, a method that doesn’t
provide any way to modify that f. Compare the following two
types:

fmap :: (a -> b) -> f a -> f b

fmap :: (a -> b) -> Either x a -> Either x b

Either x is essentially just replacing the f everywhere. Maybe adding


some redundant parentheses will help us better appreciate this
correspondence.
fmap :: (a -> b) -> f a -> f b

fmap :: (a -> b) -> (Either x) a -> (Either x) b

And, you see, there is no way to modify that Either x. If there was
one, we would have an extra input parameter to fmap indicating
how to modify that x on the Left, but alas, we don’t have one. All
we know is how to modify that a, the one on the Right, into a b.

There are kinds beyond Type, Type → Type, Type → Type → Type, etc.
However, for the time being we don’t care. And anyway, we have
learned enough about this topic for now, so let’s continue our
journey, comfortable with this new knowledge.
52. Kind of fun
Let’s go back to our goal of coming up with a Functor instance for
functions. The first thing we need to acknowledge is that we must
be able to talk about functions as something of kind Type → Type
somehow, since this is what the Functor typeclass mandates. How,
though? Functions like Natural → Natural or a → b are expressions,
values of kind Type, not type constructors. Well, Maybe Natural and
Either a b were Types as well, yet somehow we managed
nonetheless. We simply left the type partially applied, and that
seemed to do the trick. How do we partially apply the type of a
function, though? It might help to learn that the arrow → in a
function type like a → b is an infix type constructor of kind Type →
Type → Type. So when we see a function Type like a → b, we must
realize that we are looking at →, the type-constructor for functions,
being applied to two other Types a and b.

Let’s do something beautiful. Let’s have the types guide us. Many
times, when programming, we have no idea what a solution could
look like, why a problem has been encoded in the way it has, or
what the problem is at all. And most times, actually, it doesn’t
matter. To the disappointment of the salesman, everything is more
or less the same. So we willingly embrace this ignorance and rely on
parametricity, this idea that a polymorphic function like fmap must
always behave the same no matter what values it will deal with.
Let’s do this step by step.

First, we just said that the arrow → in a function type like a → b is an


infix type constructor, and we learned before that infix operators
can be used in a prefix way if we just sprinkle some parentheses
around them. Let’s do that. a → b is exactly the same as (→) a b.
That is, for example, the type of a function Natural → String could
also be written as (→) Natural String. Of course, it looks ridiculous,
that’s why we never write it this way, but at times it can be
necessary. Times like now. The kind of (→) Natural String, a
function type, a type like any other, is Type. The kind of (→), the
type constructor which takes two Types as arguments, here Natural
and String, is of course Type → Type → Type. The first type parameter,
Natural in our example, corresponds to the type of the input of this
function, whereas the second parameter, String here, corresponds
to its output. And what if we apply just one of those two
parameters, say, Natural? We end up with (→) Natural of kind Type →
Type, the kind Functor desperately wants. (→) Natural is a type
constructor for a function that takes a Natural number as input, it
says nothing about what the output type of said function will be.
But of course, (→) Natural is unnecessarily restrictive. What do we
care what the type of the input is? Let’s spice up the mystery and
use (→) x instead.

instance Functor ((->) x) where …

Alright, (→) x has the exact kind Functor expects, so in theory it


could be a functor if we somehow manage to implement the fmap
method in a way that it abides by the functor laws. What would
fmapping a function over (→) x do, though? Hard to fathom, but
also completely irrelevant. We can still go ahead and implement a
correct fmap that will do what it must. Let’s look at what the type of
fmap looks like when we specialize the f in Functor f to (→) x.

fmap :: (a -> b) -> ((->) x) a -> ((->) x) b

Ugh, let’s clean that up. First, those parentheses around (→) x are
unnecessary: ((→) x) y and (→) x y, for any choice of y, mean the
same. Let’s get rid of them.

fmap :: (a -> b) -> (->) x a -> (->) x b

Second, (→) x y and x → y —again, for any choice of y, including


our a or our b— mean exactly the same, so let’s use the latter,
allegedly easier on the eyes, form.

fmap :: (a -> b) -> x -> a -> x -> b

Oops, our fmap now seems to take four parameters as input rather
than two. It’s alright, we just forgot to add parentheses to prevent
the arrows → belonging to f from getting intertwined with the ones
that are part of fmap's own type.

fmap :: (a -> b) -> (x -> a) -> (x -> b)

Finally, this is where we wanted to be. Here, fmap is a function that


takes two other functions as input, a → b and x → a, and somehow
returns a function x → b. In other words, given an x, fmap uses the
function a → b to transform the a output of the function x → a into
b. For all of this to work, however, we need an x to provide to our x
→ a function. Without it, we won’t be able to obtain an a to which
we can apply our a → b. Well, that’s not a problem at all. It might
help to remember that the rightmost parentheses, the ones
surrounding x → b, are optional.

fmap :: (a -> b) -> (x -> a) -> x -> b

Look at that, an x. It seems we have everything we need. We simply


apply x → a to x, and to the resulting a we apply a → b in order to
finally return that b. Easy.

instance Functor ((->) x) where


fmap = \g f x -> g (f x)

Done. We had no idea what to do, we just more or less knew where
we wanted to go, we let parametricity guide us, and we got there
anyway. We can be certain our implementation is correct because
there is simply no other way of implementing this. Try all you
want, but aesthetics aside, you’ll end up here again. We are home.
We are where we need to be.

So when they ask if you can do something, take their money and
say yes. You know parametricity and they think their problem is
special. You will be fine. Just kidding. Don’t do that. Be a
responsible professional. The point is that you can always rely on
parametricity, the ultimate trick.

But not only is this the solution we didn’t know we were looking
for, it is also a beautiful place. Look harder at the type of our fmap.
What do you see? Nothing? Are you sure? What about if we just
rename some of the type parameters?

fmap :: (b -> c) -> (a -> b) -> (a -> c)

Don’t you recognize it? Alright, here it is:

compose :: (b -> c) -> (a -> b) -> (a -> c)

In other words, the Functor instance for functions explains how


functions compose together. That is, wherever f is a function,
saying compose g f is the same as saying fmap g f. Something like
fmap add_one multiply_by_ten 3, for example, would return 31 just
like compose add_one multiply_by_ten 3 or (3 * 10) + 1 would. In
fact, we can simply reuse compose as our definition of fmap.

instance Functor ((->) x) where


fmap = compose

And there is no container, no. Yet here we are, with a perfectly


acceptable functor. So this is the last time we talk about functors as
containers. Or do you, by any chance, see a value contained
somewhere? I thought so. We’ll explain the true nature of functors
later on.
53. Equational reasoning
That functions are functors, among other things, means that
compose not only is useful and necessary at times, but that it also has
a strong mathematical foundation telling us why it won’t ever go
wrong. How? Well, if functions are functors, and if functors are
expected to abide by the functor laws known to guarantee a correct
behavior, then compose, also know as fmap, must do so as well. Let’s
prove it.

The first functor law, the identity law of functors, says that
fmapping id over our functor shall result in that same functor,
unmodified. In other words, for any function f, f and fmap id f are
equal. We will use a very straightforward and mechanical technique
to show that this is indeed the case.

In Haskell, when we say a = b, we are saying that the expressions a


and b are equal. This implies that whenever a appears in an
expression, we can replace it with b —or vice-versa— and the result
should be exactly the same. We sometimes refer to this as
substitution, seeing how we substitute one expression by another
one. By repeatedly substituting expressions with an equal one, we
can try to prove that two expressions of our choice are equal. We
call this process equational reasoning. Let’s try it. Using this
approach, let’s prove that f and fmap id f, both of the same type a →
b, are equal.

First, we write down fmap id f as a starting point, hoping that at


some point that expression will become f.

fmap id f
We should clarify that we won’t be writing a Haskell program here,
we will just write down expressions that happen to be equal to the
previous one we wrote. This is the kind of logical reasoning that
you can do on a piece of paper. Eventually, if true, we will get to say
that fmap id f is indeed equal to f.

The second thing we will do is to replace fmap with its definition


right here, where we are referring to fmap by name. Or, as we say, we
inline the definition of fmap in our expression:

(\h g x -> h (g x)) id f

We didn’t inline the definition of fmap because it was the only thing
to do, we only did it because it was one of the possible alternatives.
We could have replaced id with its definition instead, and it would
have been fine as well. We just needed to start somewhere, so we
made an arbitrary choice.

Next, we can beta-reduce the first argument to our fmap function.


That is, we will have id take the place of h in fmap's body, and
remove h from the input parameters of the lambda expression:

(\g x -> id (g x)) f

We can now beta-reduce the first argument to our \g x → …


function, having f take the place of g. We will remove some
unnecessary parentheses as well.

\x -> id (f x)

We know that applying the identity function to some expression


results in that same expression. Here, saying id (f x) is the same as
saying f x. So let’s just get rid of the id application and that way
save a few steps in our equational reasoning.

\x -> f x

Finally, we also learned about eta-conversion, which says that \x → f


x is the same as saying just f. So let’s get rid of that redundant
lambda expression.

Alright. Using substitution and equational reasoning we went from


fmap id f to f, finally arriving to the trivial truth that f equals f. It
was easy, wasn’t it? Yet, using such a rudimentary and mechanical
approach we managed to prove that our implementation of the fmap
method for functions abides by the first functor law. We can prove
a surprisingly large number of things with this one trick.
54. Shadow
Armed with our new knowledge, we proceed to tackle the second
functor law, which says compose (fmap g) (fmap f) a should equal
fmap (compose g f) a. Well, let’s see if it is true using equational
reasoning. We’ll do it in two steps. First, let’s reduce fmap (compose g
f) a as much as possible. Reducing, in this context, means means
repeatedly using beta-reduction, substitution, eta-conversion, and
similar techniques to replace function applications for the actual
expressions that those applications eventually become. We start by
writing down the expression that concern us.

fmap (compose g f) a

Here, all of g, f and a are functions. We know that g and f are


functions because compose always expects functions as its input
parameters, so there is no way they could be something else.
Regarding a, we know it is a function simply because we are saying
it is. That’s all. Remember, here we are trying to prove that using
fmap with functions behaves in a particular manner, and that
necessarily means that we will pick our second parameter to fmap to
be a function, and not something else.

Now, since we already now that the fmap definition for functions is
just compose, we can simply replace the name fmap for the name
compose in our expression in order to make things simpler.

compose (compose g f) a

It’s also important to keep in mind that g, f and a are just names we
are making up here, names of expressions, and they have no direct
correspondence to the fs and as we have been encountering in
places such as class Functor f or fmap :: (a → b) → f a → f b, where
not only are those the names of types and type-constructors, not
expressions, but they are also made up. During this equational
reasoning exercise we are only paying attention to expressions, not
to types.

Back to compose (compose g f) a. There’s no way to reduce that


expression unless we fully substitute compose with its definition, so
let’s do that in both occurrences of compose.

(\g f a -> g (f a)) ((\g f a -> g (f a)) g f) a

That’s perfectly valid Haskell, it turns out. All we did was


substitute compose with its implementation \g f a → g (f a) and add
some necessary parentheses. It looks rather cryptic, though. The
main problem seems to be that we are repeating f, g and a
everywhere, which makes us a bit dizzy. However, this is “fine”.
When we say something like (\x → x) (f x), the x in \x → x is not
the same as the x in f x. Remember, in \x → … we are making up a
new name, here x, which we will use within this lambda expression
to refer to any input that it is provided to it. Whether somebody
called something else x outside this lambda expression is irrelevant,
because this x name we are binding in our lambda expression will
shadow any other x that exists outside the lambda expression.

Shadow? Compare (\x → x) (f x) with (\y → x) (f x). The former


is essentially the identity function applied to f x, whatever that
might be, so the result of the entire expression is f x. The latter
example is applying a function \y → x to f x. Now, this function \y
→ x is saying that it will take something as input, which it will call y,
it will ignore it, and it will return x instead. Which x? Well, the same
x that f is being applied to, the x that exists even outside the lambda
expression, the x that the former example shadows instead. We
haven’t really seen that x being bound anywhere, but that doesn’t
concern us at the moment, we can assume somebody else did that
for us.

It’s like you have a neighbour, Andrea, who you only run into from
time to time. You go back to your place, and maybe you tell your
partner about how you ran into Andrea in the hallway, or how
Andrea rang your bell the other day, asking if we had a tool he
didn’t have. Whenever you or your partner say “Andrea”, you both
know with certainty that you are talking about that neighbour.
Andrea is part of your daily life, of your environment, so you make
sure you remember his name. One day, however, a friend from
your childhood comes to visit you. A friend that just for one day
becomes a part of your private environment, of your home. She is
also called Andrea. In that home, that day, if you talked to your
partner about somebody named Andrea: Who do you think will
come to mind first? The neighbour who is out there, or the
childhood friend who is with you today? That’s right. Andrea, the
name of our friend, shadows the name of our neighbour, even if
only for that day, in that home.

There are very simple rules to identify with certainty the expression
to which we refer when we mention a name anywhere in our code.
We will learn them very soon, but for now let’s go back to our more
immediate concerns.
55. α-conversion
We are still in the middle of our journey, trying to prove the second
functor law for functions by using equational reasoning to
demonstrate that compose (fmap g) (fmap f) a and fmap (compose g
f) a are the same. We decided to start by reducing fmap (compose g
f) a, and we ended up with this:

(\g f a -> g (f a)) ((\g f a -> g (f a)) g f) a

We have way too many fs, gs and as in our code, and that is a bit
confusing. We know that because of the shadowing of names,
Haskell doesn’t care. Haskell can still figure out the meaning of this
without any cognitive overhead. But we, the fragile humans,
struggle. So let’s use a tool to help us navigate this mess.

The identity function is implemented as \x → x. Or was it \a → a?


Ah, no, it was \motorcycle → motorcycle, right? You see, it doesn’t
matter. Names are made up, names are used, and as long as we are
consistent it doesn’t matter which names they are. It is alpha-
conversion, or α-conversion, yet another lambda calculus feature,
which explains how this is possible. Essentially, functions such as \x
→ x and \y → y are alpha-equivalent versions of each other, meaning
that while they are not literally equal because they bind expressions
to different names, they still mean exactly the same. We move
between these versions by a process of alpha-conversion, which
consists pretty much of just replacing a name with another one
everywhere it appears bound to the same expression. Don’t you like
x? You cringe at the sight of \x a → (a, x)? Would you rather have y
there? Then alpha-convert to \y a → (a, y) and presto. We
sometimes say alpha-renaming instead of alpha-conversion. It is
exactly the same, as if alpha-conversion itself had been alpha-
converted.

Anyway, let’s α-convert some of those fs, gs and as to make things a


bit more obvious.

(\i h b -> i (h b)) ((\k j c -> k (j c)) g f) a

We kept our original f, g and a as they were in fmap (compose g f) a,


but we alpha-renamed the ones inside our inlined versions of fmap
and compose, the ones that were shadowing our original ones. And
while we now have more names to consider, we also have less
opportunities to mistake one for the other. So thank you, α-
conversion, for supporting our existence as imperfect human
beings.
56. Churn
Alright, let’s continue reducing our fmap (compose g f) a until we
get to the point where we can’t do it anymore. This might get
boring, so feel free to just skim over the details while you yawn.

(\i h b -> i (h b)) ((\k j c -> k (j c)) g f) a

First, through beta-reduction, let’s get rid of that k by substituting


it with g.

(\i h b -> i (h b)) ((\j c -> g (j c)) f) a

Similarly, we get rid of that j, by replacing it with f.

(\i h b -> i (h b)) (\c -> g (f c)) a

Now we can do the same with i, this time substituted with all of \c
→ g (f c).

(\h b -> (\c -> g (f c)) (h b)) a

We now do the same for h, substituting it with a.

\b -> (\c -> g (f c)) (a b)

And finally, we substitute c with a b.

\b -> g (f (a b))
There’s nothing else to do. fmap (compose g f) a reduces to this at
best. All we have to do now is reduce compose (fmap g) (fmap f) a
and see if we end up with the same expression. If we do, it means
that fmap (compose g f) a and compose (fmap g) (fmap f) a are
indeed the same, which proves the second functor law for
functions. Let’s do it faster this time.

compose (fmap g) (fmap f) a

First, let’s inline the definitions of compose and fmap, which we know
are the same. As we do it, let’s also use alpha-conversion to make
sure we pick different names so that this is easier for us humans to
follow.

(\i h b -> i (h b)) ((\k j c -> k (j c)) g)


((\m l d -> m (l d)) f)
a

Oh my, how tiresome. Let’s beta-reduce that k, substituting it with


g.

(\i h b -> i (h b)) (\j c -> g (j c))


((\m l d -> m (l d)) f)
a

And the m, which becomes f.

(\i h b -> i (h b)) (\j c -> g (j c))


(\l d -> f (l d))
a
And the i now, which we substitute with all of \j c → g (j c).

(\h b -> (\j c -> g (j c)) (h b)) (\l d -> f (l d)) a

And also the h, which will become all of \l d → f (l d).

(\b -> (\j c -> g (j c)) ((\l d -> f (l d)) b)) a

Oh, and now we can beta-reduce that b, replacing it with that a.

(\j c -> g (j c)) ((\l d -> f (l d)) a)

And the l goes away too, it becomes the a.

(\j c -> g (j c)) (\d -> f (a d))

Now it’s time to beta-reduce that j. The function \d → f (a d) will


take its place.

\c -> g ((\d -> f (a d)) c)

And we can get rid of that d as well. We can substitute it with c.

\c -> g (f (a c))

And we are done. There’s nothing left to reduce, luckily. So, have
we proved anything? On the one hand we had fmap (compose g f) a,
which reduced to \b → g (f (a b)), and on the other hand we just
reduced compose (fmap g) (fmap f) a to \c → g (f (a c)), which is
not exactly the same. Or is it? Aren’t we forgetting what our friend
alpha-conversion is capable of? These two expressions are alpha-
equivalent, we just ended up binding the name b on one of them
and c on the other, but the meaning of these expressions is the
same: We take a value as input, apply the function a to it, then
apply f to this result, and finally apply g to all of that.

\sandwich -> g (f (a sandwich))

So yes, fmap (compose g f) a is equal to compose (fmap g) (fmap f) a,


which means that function composition abides by the second
functor law. And, considering how function composition also
abides by the first functor law, we can solemnly claim that
functions are indeed proper functors, as witnessed by the existence
of the Functor instance for (→) x.
57. Performance
Even while both compose (fmap g) (fmap f) a and fmap (compose g f)
a eventually reduced to the same expression, one did it in less steps
than the other. Concretely, it took five beta-reductions for fmap
(compose g f) a, whereas it took eight for compose (fmap g) (fmap f)
a. What does this mean? Well, semantically, not much. After all, we
did get to the same result. However, as fast and obeying as our
computers may be, they still need to do all we ask of them. They
don’t skip any work. So if we ask them to do something five times,
they will necessarily do that faster than if we ask them to do it eight
times. So we need to be aware of these things, too.

Any time a computer spends doing something is time not spent


doing something else. That’s not necessarily bad, though. After all,
we have these computers so that they do as much work as possible
for us all day long, but it is a fact we must acknowledge nonetheless.
In particular, while a program is still computing something, it is not
yet delivering the results of that computation to whomever is
expecting them. Generally, we want our programs to be as fast as
possible, so it’s important that we understand not only the meaning
of our programs, but also how fast they perform so that we can act
accordingly or optimize them if possible. Not always, tough. Think
of the traffic light that waits a couple of seconds before changing
colours. That delay is artificial, the colours could change much
more rapidly, but we deliberately make the switching of the colours
slow to give traffic enough time to go through. Moreover, not
everything deserves to be as fast as possible, even if desirable from
an execution time point of view. Like everything else in life that is
valuable, speed has a cost. A cost that often manifests itself in how
much time we humans spend making things fast, time that could be
better spent, arguably, on making sure our program is correct,
talking with friends, or building something else.

How do we know when speed is a worthy goal? Well, we get our


priorities right and decide. Sure compose (fmap g) (fmap f) is slower
than fmap (compose g f), but does it matter? Well, not if we are
running it every once in a while, but quite likely it does if we are
doing it a substantial number of times. Unless our program is
expected to be the fastest one, in which case we sacrifice everything
in the name of speed. Or unless speed is not particularly important,
in which case we mostly ignore this. How substantial must a
difference in performance be? Can we measure that? Yes, yes we
can. But be warned, there’s a bit of folklore involved, though.
Unfortunately, while we have things such as types for helping us
reason about the semantics of our programs before they even exist,
tools for reasoning about performance are less sophisticated and
mostly rely on thinking really hard, pen and paper, or measuring
after the fact. On the other hand, modern compilers can sometimes
realize on their own that something can be made faster without
affecting the semantics of our program, and they will magically go
ahead and optimize things for us. However, this only goes so far.
We can’t, for example, expect compilers to optimize programs that
are conceptually inefficient by design, like doing complex
arithmetic calculations with that beautiful but slow inductive
representation of natural numbers from before.

It’s worth noting that while it is easier to talk about performance in


terms of time and speed, performance can be measured in other
ways as well. Insofar as computers are concerned, for example, we
can consider how much space, or memory, a particular program
takes. But even beyond the computer, we can talk about how
quickly something can be implemented, how many people need to
be involved, or what kind of resources we need.
So yes, this is a book on economics too. It must be if we expect this
type of programming to be realistic, to be relevant to civilization at
all. But we are still just getting started, so let’s mainly focus on
getting our programs right for the time being. We’ll come back to
this later.

Oh, and by the way, that thing about fmap (compose g f) being
more performant than compose (fmap g) (fmap f)? It turns out that
this has impressive implications in the large. We’ll see this pop up
time and time again as a magic trick to make our programs faster in
our studies.
58. Fleither
A while ago we struggled with the Left. We learned that fmap wasn’t
able to do anything with the value contained in a Left constructor,
it was only able to cope with the one on the Right one. It had
something to do with kinds. Essentially, the Functor typeclass
expects its instances to be defined for type-constructors of kind Type
→ Type, where that input Type is necessarily the rightmost type
parameter in our type constructor. So, for example, Either x,
because of its kind Type → Type, is a suitable candidate for a Functor
instance. And what happens to the type of the fmap method in this
instance? It becomes (a → b) → Either x a → Either x b, a function
that suddenly can only modify the payload on the Right. Nothing
interesting happens on the Left.

What if we flip it, though? What if Either x y meant that x was the
type of the payload on the Right, and y the type of the one on the
Left? Well, in the Functor instance for this brand new Either x, also
of kind Type → Type, we would still get fmap :: (a → b) → Either x a
→ Either x b. That static x however, the one that stays the same,
would now be talking of the Right payload, not the Left. And vice-
versa, of course, which means that fmap would indeed allow us to
modify the Left. The problem, however, is that we can’t do that.
Someone other than us came before, created Either the way we first
met it, and shipped it with the Haskell language as such. We are
kind of stuck with it, forever, we have to embrace it as it is. What
can we do?

One thing we can try is to create a new datatype isomorphic to


Either but with its type parameters flipped, so that its Functor
instance works on the Left rather than the Right. Let’s call it
Fleither, short for “flip Either”.
data Fleither a b = Fleft b | Flright a

Look how the b type parameter, the one our fmap method would
allow us to modify, is now on the Fleft as we wanted.

instance Functor (Fleither x) where


fmap = \g s ->
case s of
Fleft b -> Fleft (g b)
Flright a -> Flright a

So clever. So much so that we neglected the Flright this time. How


do we fmap a function over the Flright side of a Fleither? We can’t,
not with this approach. Let’s throw Fleither away, we need
something else.
59. Flip
When defining a new datatype like Either, Fleither or Pair, we
don’t always have to start from scratch, leaving all the payloads that
show up in our fields polymorphic. Sometimes we can be a bit
more concrete, and it works too.

data Flip b a = Flip (Either a b)

Here we are defining a new datatype named Flip, with two type
parameters b and a. This datatype has a single constructor, also
called Flip, which takes an entire Either a b as payload. That is, we
construct a Flip by saying either Flip (Left …) or Flip (Right …).
The interesting thing to notice is that the type parameters in Flip b
a and Either a b are flipped, which would force a Functor instance
for Flip b to target that a on the Left, rather than the b on the Right
as fmapping over Either a b would normally do.

instance Functor (Flip x) where


fmap = \g s ->
case s of
Flip (Left a) -> Flip (Left (g a))
Flip (Right x) -> Flip (Right x)

There’s nothing new here, we are just pattern-matching on the Flip


constructor to extract its payload so that we can modify it if
necessary. Of course, after modifying the payload on the Left
constructor, we need to wrap the modified Either in the Flip
constructor again. And similarly on the Right side. The type of fmap,
which has now become (a → b) → Flip x a → Flip x b is demanding
it. In other words, that s expression we are pattern-matching on has
type Flip x a, and both expressions the right of the arrow → have
type Flip x b.

Ok, so how is Flip better than that failed Fleither from before?
Well, it is still not ideal, so if that’s what we are looking for we are
not going to find it here. But look at this:

foo :: Either Natural Season


-> Flip [Temperature] String
foo = \x -> fmap bar (Flip (fmap qux x))

Can you tell what this horrible yet didactic function does? What
would be the result of foo (Left 3)? What about foo (Right
Winter)? Well, it doesn’t matter what the exact result would be, but
suffice to say that the bar function we assume here would transform
that Natural number 3 on the Left side of the Either into a String
somehow, and the qux function would transform the Season on the
Right into a [Temperature]. Remember, the type-level parameters to
Flip appear deliberately in the opposite order than those in Either
do, let’s be aware of that. The interesting thing in this exercise is
that we manage to target both sides of an Either by relying solely on
the behaviour of fmap. Unfortunately, we always end up with a Flip
rather than an Either as output. For example, foo (Left 5) could
result in the value Flip (Left "bird") rather than just Left "bird".
Luckily, that’s quite easy to fix. We just need to remove that
wrapper. After all, it doesn’t serve any purpose after we are done
fmapping over it.

unFlip :: Flip a b -> Either b a


unFlip = \(Flip x) -> x

Other than the weird name unFlip, suggesting some kind of


undoing, there should be nothing surprising here. We are just
pattern matching on the Flip constructor to extract its payload
before returning it. We know this x has the right type, an Either
with its type parameters flipped, because that’s what it says,
literally, in the definition of this datatype. We can use a
straightforward lambda expression to extract this payload because
the Flip a b datatype has only one constructor. Otherwise, we
would have needed to perform a case analysis to inspect all possible
constructors. Long story short, unFlip will discard that Flip
wrapper, so let’s put it to use in our also awkwardly named
function foo.

foo :: Either Natural Season


-> Either String [Temperature]
foo = \x -> unFlip (fmap bar (Flip (fmap qux x)))

Alright. The implementation seems a bit convoluted, but


remember that we mostly just look at the types of things after we
are done with them, not at the expressions that implement them.
And here we just see that we go from one Either to another Either,
not one detail about Flip leaks to the type of our function.
Safeguarding the programmer from the ugly truth, hiding the bad
stuff under the carpet, only ever looking at nice things: This is what
software development is about. Just kidding, it is not. But still, one
has to acknowledge the beauty of being able to prevent irrelevant
implementation details, such as that Flip thing, from becoming a
cognitive burden to whomever is trying to understand the purpose
of this function. Kind of.
60. bimap
Granted, due to the lack of parametricity, our function foo is not
the shinning light it’s been made out to be. For all we know,
without looking inside foo, this function could be simply ignoring
its input and returning always Left "crocodile". Why not?

The problem, once again, is that we know too much about the
payloads that go into that Either. We need to forget. How? Why
with parametricity, of course. So, rather than going from an Either
Natural Season to a Either String [Temperature], we will go from an
Either of mysterious things to an Either of even more mysterious
things. Let’s make up some names.

foo :: Either a b -> Either c d


foo = \x -> unFlip (fmap ‽ (Flip (fmap ‽ x)))

The problem, now, is that we don’t know what to write where we


left those ‽ placeholders. Think about it. How will we modify a so
that it becomes c, or how would we modify b so that it becomes d, if
we know nothing about neither a, b, c nor d? Well, we would not.
But that’s fine, that’s what we wanted. It’s so easy to forget why we
are here sometimes. So what do we do? Well, what does fmap do
when it wants to modify the Right side of an Either, say, without
knowing what’s in it exactly? It simply defers the decision of how
to modify that payload to the callers of this function, by asking
them to provide the function that will modify the payload.

fmap :: (a -> b) -> Either x a -> Either x b

Let’s copy this, then, but taking two functions rather than one.
One for each side.

foo :: (a -> c) -> (b -> d) -> Either a b -> Either c d


foo = \l r x -> unFlip (fmap l (Flip (fmap r x)))

Sure, foo doesn’t apply our fantasy bar nor qux on its own anymore,
but that’s alright, we could now say foo bar qux to achieve the same
result. That’s what we wanted, after all. Now, originally we named
this thing foo because, this function being as ugly as it was, didn’t
deserve a better name. We punish ad-hoc code by not giving it a
decent name, that’s what we do. It keeps us from developing
affection for it. But now, behold, foo is one with beauty, so let’s
give it a proper name.

bimap
:: (a -> c) -> (b -> d) -> Either a b -> Either c d

It is a nice name, bimap. It evokes the idea that, somehow, we are


mapping over two things. And indeed, that’s exactly what we are
doing.
61. Bifunctor
What about Pairs? We kind of forgot about them, but remember,
just like Either is the most fundamental sum type out there, Pair is
the most fundamental product type, so we need to pay attention to
it as well. We can’t forget it. Let’s recall the definition of Pair.

data Pair a b = Pair a b

So, while Either a b has one of either a or b depending on whether


we use the Left or Right constructor, Pair has both a and b values in
it, always. Can we imagine mapping over both of them? Sure.
Maybe we have a Pair Natural Season and we want to convert it to a
Pair String (Maybe Temperature) for some reason. There’s nothing
wrong with that. So how do we do it? Well, let’s just copy what
bimap did, but this time for Pairs.

bimapPair
:: (a -> c) -> (b -> d) -> Pair a b -> Pair c d
bimapPair = \f g (Pair a b) -> Pair (f a) (g b)

Alright, this works. We bind f to one of the functions, g to the


other one, we pattern match on the a and b payloads of our Pair
constructor, and after applying f and g to them, respectively, we
put them back in a new Pair and we send them on their way.
Beautiful.

Wait a minute. There’s a pattern here. Let’s compare bimap with


bimapPair.
bimap
:: (a -> c) -> (b -> d) -> Either a b -> Either c d

bimapPair
:: (a -> c) -> (b -> d) -> Pair a b -> Pair c d

Other than bimapEither allegedly being a more precise name for


bimap, what do we see? The only thing that changes is our choice of
Either or Pair, everything else in these types stays the same. We’ve
seen this before, when somehow we managed to put all of (a → b) →
List a → List b, and (a → b) → Maybe a → Maybe b and the like under
the same umbrella. What did we reach out for? Functor. And what
was Functor? A typeclass with a single method fmap that let us
operate on different functor-like things homogeneously. Well, it
turns out Functor is not the only interesting typeclass out there. We
have others, like Bifunctor here:

class Bifunctor (f :: Type -> Type -> Type) where


bimap :: (a -> c) -> (b -> d) -> f a b -> f c d

This should be straightforward, all things considered. First, notice


how we gave f, the bifunctor-like thing, an explicit kind Type → Type
→ Type. In instances of this typeclass, this f will become type-
constructors such as Either or Pair, taking two other Types as input.
We kept the name bimap for the method in this typeclass. Why
change something so beautiful? Hopefully we can see how
replacing that f with concrete type-constructors like Either and Pair
leave us with a type of bimap specialized for types as concrete as
Either a b, Pair c d, etc. Let’s see some instances of this typeclass.
instance Bifunctor Pair where
bimap = \f g (Pair a b) -> Pair (f a) (g b)

There should be nothing surprising in the Bifunctor instance for


Pair. We just wrote the same implementation we had in our ad-hoc
bimapPair.

instance Bifunctor Either where


bimap = \f g x ->
case x of
Left a -> Left (f a)
Right b -> Right (g b)

Nothing surprising in this instance either. This time, however, we


decided against re-using the implementation that used that Flip
trick to target the Left. Why? Well, mainly because we can, but also
because this way is more performant. Think about it. Here we are
pattern-matching once, that’s all, but in our Flip example we were
indirectly pattern-matching once each time we used fmap, and we
called fmap twice. So this implementation, in theory, should be at
least twice as fast. Further optimizations made automatically for us
by the compilers might render this argument moot, they might see
the two fmaps, the Flip and the unFlip, and simplify all of that
somehow. But still, it’s important that we start getting familiar with
how to measure performance. Anyway, whether our performance
optimizations have merit or not, this implementation looks quite
straightforward, so let’s keep it.

With these instances in place, bimap (add 1) (add 10) will take us
from Pair 2 5 to Pair 3 15, from Left 2 to Left 3, from Right 5 to
Right 15, and the like.
62. Swap
Here’s a quick interlude, a curiosity. We just learned that the bimap
method of the Bifunctor typeclass allows us to comfortably work on
both the as and bs showing up in types like Either and Pair. And
seeing how as and bs are all these types have inside, we should be
able to tackle anything concerning Either, Pair and the like using
just bimap. Right? Not so fast. Consider the swap function.

swap :: Pair a b -> Pair b a


swap = \(Pair a b) -> Pair b a

Like the identity function, swap is one of those functions for which
there’s only one possible implementation. It’s parametricity, again,
telling us what to do. Anyway, that’s beside the point. We are
trying to focus on something else here. We are trying to address
how to implement swap in terms of bimap. It should be possible, if
bimap is as powerful as we made it out to be.

swap :: Pair a b -> Pair b a


swap = \x -> bimap ‽ ‽ x

Well, well, well… it seems bimap is not as powerful after all. Let’s
recall the type of bimap.

bimap :: Bifunctor f
=> (a -> c) -> (b -> d) -> f a b -> f c d

In our case, the chosen f, our Bifunctor, is Pair. Let’s specialize that.
bimap :: (a -> c) -> (b -> d) -> Pair a b -> Pair c d

Moreover, the expected output type is not Pair c d, but rather Pair
b a. We can replace c with b and d with a throughout to convey this.

bimap :: (a -> b) -> (b -> a) -> Pair a b -> Pair b a

Alright. So, all we need to do is have the first function, the one that
modifies the a value as it appears in the input Pair a b, return the b
value that appears in that same input. And vice-versa in the case of
the second function. Alas, we can’t.

While in Pair a b we can say that a and b exist in some kind of


context where they are each other’s neighbour, bimap forgets about
that neighbourhood and only allows us to address the values
individually, forgetful of the context in which they exist. We can’t
ask a who its neighbour is, we would need to be observing both a
and b at the same time —that is, in the same function, as swap
does— in order to answer that. The fact that we have a → b and b →
a separately makes this impossible. So no, we can’t use bimap to
implement swap, for any implementation of swap needs to know
about the value next door.

Is this bad? No, not necessarily. Understanding and relying on the


limitations of our abstractions is fundamental to this type of
programming. Imagine a Pair MyMoney YourMoney. If we only ever
have Bifunctor as a means to operate on this Pair, then we can be
certain that our monies will never mix, and that is good. In time, we
will learn about more neighbourly abstractions.
63. Bifunctorn’t
So what else is of kind Type → Type → Type? Why, functions of
course. And by functions we mean the (→) type-constructor, the
one we shoehorned into the Functor typeclass by partially applying
it to just one Type, rather than two. Here, however, the Bifunctor
typeclass asks us for something of kind Type → Type → Type. So
proud of itself, feeling welcome, the function goes…

instance Bifunctor (->) where …

… and then it dies. Just ponder at the apparent beauty, the abyss, of
the type bimap gets for a function.

bimap :: (a -> c) -> (b -> d) -> (a -> b) -> (c -> d)

It says that given our function a → b, the one we are attempting to


modify, and two other functions a → c and b → d, it can transform it
to a new function c → d. We saw in fmap, just a different name for
compose, how two functions b → d and a → b can come together to
form a function a → d, where that d is the result of applying b → d to
the b we obtain from applying a → b to the a we will eventually
receive as input. And if we put fmap and bimap side by side, we will
see that things are not that different.

fmap :: (b -> d) -> (a -> b) -> (a -> d)


bimap :: (a -> c) -> (b -> d) -> (a -> b) -> (c -> d)

The mystery, the conundrum, must thus be in c, the one type that
fmap doesn’t mention at all.
If we look at what bimap returns, we see a function that receives a c
as input, and somehow returns a d as output. Well, let’s try and find
the ways we could obtain a d. There is a b → d function, which
implies that if we somehow manage to get our hands on a b, then a d
will easily follow. Alright, let’s get a b then. There is a function a →
b that returns a b if we just give it an a. Well then, let’s find a a. Oh,
the disappointment. There’s no a, and there is no way to obtain one
either. All we have is a c, a bunch of functions we can’t use, and the
queen of them all, a → c, just shamelessly laughing at us. How did
we end up here? We need c → a, not a → c. Who flipped that arrow?
We have the c already, it’s the a the one we need, not the other way
around. Just flip it. Flip it. Flip it! Ahh!

So this is the place. This is where many a programmer has lost it.
And understandably so, for this is a fundamental problem we are
facing. But we are going to get through this, don’t worry, and
things will be much, much brighter on the other side. It will be
alright.
64. Quantification
Let’s have a quick interlude before we continue. We have been
hiding something quite important about the types we write, and it’s
time we made this explicit.

Where do names come from? We learned that in the case of lambda


expressions like \x → …, it is in our choice of the word x, which we
write in between \ and →, where we decide that x will be the name
we will use within this lambda expression to refer to the input of
this function. But function inputs are not the only things that we
can name. Let’s revisit our beloved identity function once again.

id :: a -> a
id = \x -> x

In this id example, we opted to bind the name x to refer to the


input expression, and we opted to give the name a to the type
variable describing the type of such input. And output, yes, yes.
We know where the name x comes from, but we don’t know where
a comes from. We seem to be just using it out of the blue. And
what if, next to this definition of id, we were to define a new
expression none?

none :: Maybe a
none = Nothing

This is a perfectly valid expression. We know that Nothing is an


acceptable constructor for a type Maybe a, for all choices of a we
may want to make. none :: Maybe Natural or none :: Maybe String,
they are alright. But what about that a? Is it the same a as the one
we wrote before in the type of id? And if we use id on a Natural
number, does it mean that none must now always take the type Maybe
Natural, since we seem to have specialized that a somehow? Not
quite.

Similarly to what we saw before when we talked about name


shadowing, where we said that each time we bind a new name to an
input expression, this name shadows an equal one that existed
before, preventing them from being mistaken for each other within
the scope of the function that binds the name, type variable names
also have a similar mechanism for allocating names. It is called
quantification.

So far, the only type of quantification we’ve dealt with, and the
only one we care about for the time being, is the universal
quantification of type variables. And it turns out that this type of
quantification, being the most common and Haskell being so user-
friendly, is also the default one that Haskell infers for us unless we
somehow ask for something else. That is, when we write a type like
id's:

id :: a -> a

What is really happening, is that we are asking for this:

id :: forall (a :: Type). a -> a

That forall (a :: Type). part is universally quantifying the name a


to be something of kind Type. Meaning that within the scope where
this quantification applies, which in this case is everything to the
right of that dot ., any type among all the types that exist can take
the place of this a. And, not knowing which type that will be, we
can continue to use the name a to consistently refer to it. So this is
how type variable names come to existence: They are quantified
somehow.

How does this solve the issue of the a in the type of id being
different from the a in the type of none? Well, let’s see the properly
quantified type of none again.

none :: forall (a :: Type). Maybe a

Here, none is also universally quantifying a, meaning that within the


scope of this quantification, a can be any Type at all, which implies
that there is no need for this a to be equal to any other a that came
before or after its time, much like what happens in lambda
expressions and shadowing, where the new name we pick for the
input expression doesn’t relate nor conflict with other names, equal
or not, at all.

Does this sound redundant and boring? That’s perfect, it should.


After all, we have been dealing with universal quantification ever
since we saw our very first type, so there’s nothing conceptually
new for us here. Why does this matter, then? Well, because we
humans sometimes forget why we are here at all, and explicitly
writing our foralls will help us remember what we are dealing with.
We will see this shortly.

Of course, we can also universally quantify more than one type


variable at once, and their kinds can be something other than Type
as well. Look, for example, at the explicitly quantified type for fmap.
fmap
:: forall (f :: Type -> Type) (a :: Type) (b :: Type)
. Functor f
=> (a -> b)
-> f a
-> f b

Other than some new syntax, there should be nothing surprising


here. We learned a while ago that the f in Functor f needed to have
kind Type → Type, and here we are just making that explicit.

It’s also possible to leave out the explicit kind information for a
quantified name, whenever it can be inferred from its usage. For
example, we could have written the type of fmap without explicitly
mentioning the kinds of a, b and f, and it would have been the
same. Haskell infers that a and b have kind Type, and that f has kind
Type → Type.

fmap
:: forall f a b
. Functor f
=> (a -> b)
-> f a
-> f b

And, by the way, one last charming detail. Rather than writing
forall, we can write ∀. It’s the same, but looks arguably nicer.
Unsurprisingly, we read ∀ out loud as “for all”.

id :: ∀ x. x -> x

We’ll make use of ∀ throughout this book, for typography is our


treat and book real estate is at a premium.
65. Tragedy
At the beginning of this book, for didactic purposes, we
intentionally said something wrong. We said something about a
function of type input → output which eventually became id. Let’s
try and write a function with that type.

nope :: input -> output

Actually, let’s add some explicit quantification. It will make things


more obvious.

nope :: ∀ (input :: Type) (output :: Type)


. input -> output

Before diving into the implementation of this function —that is,


into the expression that defines it— let’s read its type out loud. It
says here that this function takes a Type as input, any Type among all
the Types that exist, and returns yet another Type as output, again,
any Type among all the Types that exist. We call these types input and
output respectively. Alright, let’s try.

nope :: ∀ (input :: Type) (output :: Type)


. input -> output
nope = \x -> ‽

Taking in that input and binding it to a name like x so that we can


refer to it afterwards is not a problem. It says in the type that input
will be a Type, any Type among all the Types that exist, and we know
that lambda expression name binding is able to cope with this. Any
input we receive, notwithstanding its type, will be bound to x.
There is nothing surprising there. The problem lies at the opposite
end, to the right of the arrow symbol →, where we are supposed to
come up with an expression of type output which, as its universal
quantification dictates, must be any Type. So do we just pick one,
then? Perhaps Natural? I mean, if we are saying any Type is fine, we
should be able to randomly pick one, right? No. Not at all. See
what happens if we do that.

bad :: ∀ (input :: Type). input -> Natural


bad = \x -> 3

Sure, this function compiles and runs. It is a perfectly valid and


boring function that ignores its input and returns a Natural
number. But where is output? Well, we said that output represented
the idea of any Type, but 3 is not any Type, it is one Type in particular,
Natural, and by saying that a Natural is what we will return, we are
implicitly saying that every other Type is what we won’t. Thus,
output disappears and a very specific Type, Natural, takes its place.

No, what our function needs to return in order to satisfy that


fantasy input → output type, literally, is an expression of any Type the
caller of this function desires. Think about how silly that is for a
second. Let’s say the caller wants the name of a flower. Well, our
function should be able to come up with one. Let’s say our caller
has a then-incurable disease and applies our function expecting a
cure in return. Guess what? We must come up with that cure, too.
But what about using x? After all, we already bound that name to
an expression of type input which we agreed represents any among
all Types, so why don’t we just reuse x? Well, here’s why.
id :: ∀ (input :: Type). input -> input
id = \x -> x

Ciao bella identità, ci siamo rincontrati. But no, id is not what we


were looking for. The identity function is something else. It takes
any Type as input, sure, but the Type that it takes, is also the one it
returns. That is, whereas input and output had been quantified
separately before, meaning the caller could have chosen an input
different than the output if desired, here these two types have been
equated, unified with each other. Whatever input is, whatever
output was, they are now one and the same Type. Or the other way
around. Remember, we have been here before, and names didn’t
matter back then either.

id :: ∀ (output :: Type). output -> output


id = \x -> x

Moreover, while moot at this point, because of the parametric


polymorphism in id we also know that the output value will be the
same as the input value, which takes us even further away from our
goal.

What we describe here with shame, a tragedy, we described before


with pride at the beginning of this book. Why? Because like
l’identità, who embraced her ignorance, and by doing so she could
reason all the way to meaning, we students must profit from our
rapidly vanishing ignorance, too, while it lasts. Did the nuances of
quantification matter sixty chapters ago? No, they did not. What
mattered was the didactic vehicle we found, the segue into
discovering something new. We’ll have time to be old, know
everything, and hinder our own learning process by not daring to
be playful anymore. So learn, never stop learning. But dare too, and
never stop playing, for it’s often in the exploration, in dismantling
the foundations and prejudices we embody, that we find new
truths worth writing.

So no, we can’t reasonably come up with an implementation for


input → output. Unreasonably however, because learning to tear
down walls is as important as learning how to build them, we can,
and we will do so now.
66. Subversion
The biggest mistake we humans make is to believe we are right
when we are, actually, wrong. Not because of how this wrong belief
might affect us, but because of the damage it makes us inflict on
others, willingly or not, and the havoc that will ensue from the
wrong choices made by the people that follow suit, also vehemently
believing the untrue. Pick any history book or news channel and
you’ll find this to be true.

So what can we programmers do to prevent this? How can we be


certain we are not wrong? Well, we start from the assumption that
we actually are wrong, and then we make sure we acknowledge any
shortcomings in our model or reasoning process, lest we disregard
or forget them later on. We achieve this by challenging ourselves, by
actively trying to subvert our own software, our own
understanding, our own beliefs. Only then, fully aware of any
limitations, and if confident that our software stands up to
scrutiny, we proceed to make the statement that is due.

To get comfortable with this subversive type of programming, we’ll


now uncover a fundamental shortcoming in Haskell’s type system.
Let’s implement the impossible input → output.

nope :: input -> output


nope = \x -> ‽

Somehow, using only what we see here, we need to come up with a


value of type output that nope can return. But how? It seems that x,
of type input, is all we have to work with. Is it, though? Let’s take a
step back so that we don’t miss the bigger picture. No, it is not. We
also have Haskell to work with. And Haskell, like every other
general purpose programming language out there, supports the idea
of general recursion, meaning that nope itself can talk about nope.
And what is nope if not a function that given a value of type input,
just like our x, returns a value of type output like the one we so
desperately need?

nope :: input -> output


nope = \x -> nope x

That’s it. We did it. We wrote a well-typed expression that our


stringent type-checker will happily accept and compile. An
expression that, suddenly, everybody can use. An expression, a
function, that given any input will return any output we ask of it.
A function that promises to name every flower, find every cure, and
do anything else we desire. With it, apparently, we have solved
every question in the universe.

But of course, none of this is real. If we dare look at the abyss for a
second, we’ll see that nope 3, say, beta-reduces to nope 3, which itself
reduces to nope 3, which again reduces to itself and forever
continues to do so. That is all there is to nope. And while to the
distracted reader this may sound a bit like what id is doing, it is
most definitely not. When we say id 3, that application reduces to 3
and there’s nothing more to reduce. But trying to reduce nope 3, on
the other hand, brings us back to nope 3. Intuitively, nope never
reduces to a smaller expression. Or, to make an analogy with
inductive recursion, it never gets closer to a base case. We saw
something like this many chapters ago, when we discussed a broken
fromNatural which got farther and farther away from its base case as
time went by.

Nope, there are no useful answers ever coming out of nope. Like a
dog trying to catch its tail, like going down Escher’s stairs, all we get
from nope is a promise, an ever lasting futile attempt, and an
innocent caller forever waiting for this function to return.
Theoretically, nope would use up all time and energy in the universe
and still fail to deliver its promise. Technically speaking, we say that
nope diverges. And that vertigo? That sense of infinity? That’s what
a paradox feels like. What happens in practice, however, if we ever
use nope, is that our program hangs. It gets stuck for as long as the
computer, unaware, continues to execute our program. Forcing the
termination of our program, perhaps by rebooting our computer,
mitigates this. Have you tried turning it off and on again? It really is
fascinating how we can model and tame the infinite within a box,
on a small piece of paper.

But this gets even more interesting, for even in this mud we can still
use our tools to improve the implementation of nope. The first
thing we can do is notice that nope is a function written in eta-
expanded form \x → nope x, which we could simplify by eta-
reducing to just nope.

nope :: input -> output


nope = nope

The tautology is now even more obvious: nope is nope. Sure, quite
helpful, thank you very much. However, something changed.
Other than its type, nothing in the definition of nope suggests it is a
function anymore. Has input → output now become an overly
specific type? If we say nope is a function, then nope = nope is simply
stating that “a function is a function”. But wouldn’t this tautology
also apply to types other than functions? Can’t we say a Natural
number is a Natural number? Can’t we say a Maybe String is a Maybe
String? Of course we can. We can say that any value of a particular
Type is indeed a value of that Type, meaning that the type of nope
could in principle be more general.

nope :: ∀ (x :: Type). x
nope = nope

Here, we are saying that nope is a value of every type out there. Do
you want to add two Natural numbers? Try nope + nope. Do you
need something to put in your Just? Maybe Just nope is your
answer. And can we compose some nopes? Sure we can, try compose
nope nope. But of course, none of these expressions accomplishes
anything, even while they all type-check. So, what does this mean?

Soon we will learn in detail that there is a direct correspondence


between types and logic, but for now, the gist of it is this: The types
that we write down in Haskell correspond to theorems in logic
—that is, statements we expect to be true— and the expressions that
we write for those types are the proofs that the theorems are true.
We briefly touched this topic before, when we talked about
isomorphism and said that we could prove that two types a and b
were isomorphic as long as we were able to implement two
functions a → b and b → a with a particular relationship to each
other. These two function types together are stating a theorem,
they are stating that it’s possible to convert between a and b and
back as necessary, which, when combined with the further
requirement that composing these two functions should result in
the identity function —although that’s beside the point—
effectively prove that a and b are isomorphic. But let’s forget about
the intricacies of isomorphisms and look at more straightforward
examples. If we manage to implement a function of type x → y, then
we are proving that we can obtain a y from an x. If we manage to
define a value of some type z, then we are proving that at least one
such value exists. And do we remember how we agreed that
implementing a Bifunctor instance for functions was just
impossible? How, in other words, we couldn’t prove that functions
were Bifunctors? Well, look again:

instance Bifunctor (->) where


bimap = nope

This, I am sorry, type-checks. Of course it is nonsense, but still, it


type-checks. What we are seeing here is that we can use nope to
prove and implement anything we want, as absurd as the type, the
premise, the theorem might be, and as useless and non-terminating,
diverging, the implementation, the proof, will be.

In literature, nope is usually called bottom or ⊥, for reasons that will


become apparent later on. In Haskell we call it undefined, which
may or may not be a reasonable name depending on our
expectations. That is, this monster comes with every Haskell
distribution:

undefined :: ∀ (x :: Type). x

In practice, Haskell’s undefined doesn’t loop forever. Instead, it


makes our program die right away, leaving a trail of forensic
memorabilia about where the homicide took place. But that’s just
an optimization. Conceptually, the proverbial infinite loop is still
somewhere in there.

Are we saying Haskell is fundamentally broken? Well, yes, but we


need to put things in perspective and understand that what we are
seeing here is merely an incarnation of the more general Halting
Problem we described before, inherent to every general purpose
programming language out there capable of computing anything
that is computable. The existence of bottom, if you will, is a proof
that given a program, any program, we can’t reliably guarantee that
it will ever terminate, that it will ever finish computing at some
point in the future.

So we buck up, we acknowledge this fundamental pitfall in our


model, in our reasoning framework, and move on. We accept that
we can’t readily trust programs written by others, and we never
bottom our own. Particularly, we never use undefined, and we are
careful not to loop ourselves into oblivion as the broken fromNatural
did. In time, we’ll find we have excellent tools for this.

But this exercise is not so much about undefined, Haskell, nor about
general purpose programming languages. It’s about understanding
our limitations and who we are. We programmers are not in the
business of lying, but in that of transparency and dealing with facts.
Knowing about our shortcomings means we can continue our
journey aware of the limb that we lack, of the allergies we have, and
still live a full factful life.

Does this make Haskell unsuitable for some kinds of problems? Of


course it does. For example, Haskell would be a terrible theorem
prover, as we would be able to prove anything we wanted with it,
true or false. There are languages that sacrifice their generality for a
bottomless existence, and in exchange they become perfect for this
task instead. We’ll see languages like these, we’ll build languages like
these. Other languages sacrifice types altogether for a stronger sense
of kinship with the computer itself, who despite seeing but
numbers, can still accomplish great things. Our toy lambda calculus
was an example of this, and we’ll see others as well. But all in all,
Haskell is an excellent place to be.
So having subverted our system, shaken but wiser, on our merry
way we go.
67. Positions
Why is it that in input → output, both types universally quantified,
we struggle so much with output yet dealing with input is so
straightforward? What is so fundamentally different between input
and output? Let’s explore that from a different angle.

We’ve grown accustomed to talking about how in a type like input


→ output we have an input parameter or argument of type input and
an output value of type output. And that is fine. But it turns out
that, actually, both input and output can be seen as arguments of this
function too, arguments with different positions. This happens to
be a richer way of describing the inputs and outputs of a function
than saying, well, inputs and outputs. So let’s learn.

We will describe nope :: input → output by saying that, from the


perspective of nope, input is an argument in negative position and
output is an argument in positive position. This means that, if there
is a need or possibility of doing so, nope would be responsible for
receiving this input and for producing this output. This shouldn’t
sound surprising, for this is exactly what we’ve come to expect nope
to do. An input goes in, an output goes out. And with these
responsibilities in mind, it’s quite easy to reason about why dealing
with output in input → output is so hard: It is nope's responsibility to
produce an output, an impossible task, whereas coming up with an
input is somebody else’s responsibility, so we just don’t worry about
it.

But we can’t really appreciate the utility of this nomenclature by


just looking at nope, so let’s look at compose instead.

compose :: (b -> c) -> (a -> b) -> (a -> c)


Which are compose's inputs? A quick glance suggests b → c and a → b,
but let’s not forget about the a that appears as an input of its own if
we remove that redundant pair of parentheses to the right.

compose :: (b -> c) -> (a -> b) -> a -> c

But even then, b → c and a → b are themselves functions, so they


clearly have inputs and outputs of their own as well. Should we add
some of them to the list of inputs to compose? Should we talk about
the input of the input? Not exactly, that would get confusing quite
rapidly, and moreover, it would be wrong. We need a better
vocabulary, so let’s talk about arguments and their positions
instead.

When we talk about argument positions, we always do so from the


perspective of one particular type. In this case, we are doing it from
the point of view of compose, so we will judge positions from the
perspective of its type (b → c) → (a → b) → a → c. Perspective is the
most important thing to be aware of when reasoning about
argument positions, so let’s make sure we always keep track of it.

We said that the arguments in negative position are those which we


receive. We already identified three of them: b → c, a → b and that
standalone a. These are the types of three values to which we can
refer by simply binding them to new names using a lambda
expression.

compose :: (b -> c) -> (a -> b) -> a -> c


compose = \g f a -> g (f a)

We bound the first argument of type b → c to the name g, the


second argument, of type a → b, to f, and the third argument, of
type a, to the name a. The fact that we were able to somehow get a
hold of these arguments, receive them, proves that these arguments
were indeed in negative position as we were told. And what about
the rightmost c in our type? Well, we know that we are producing a
value of this type c as output where we say g (f a), so this c must
necessarily be an argument in positive position. Let’s add some
annotations to keep track of what’s positive + and what’s negative -.

compose :: (b -> c) -> (a -> b) -> a -> c


-------- -------- - +

Is this all? Of course not. So far all we’ve done is say that b → c, a →
b and a are negative arguments whereas c is a positive argument. We
might as well have said they are inputs and outputs, respectively, and
it would have been sufficient. So what else is there? Let’s take it step
by step. First, let’s put those redundant rightmost parentheses back
in the type of compose.

compose :: (b -> c) -> (a -> b) -> (a -> c)

Technically, this is exactly the same as before. Conceptually,


however, rather than describing compose as the function that takes
three values as input, with types b → c, a → b and a, and returns a
value of type c as output, we now describe compose in a rather
beautiful manner as the function that given two functions b → c
and a → b, returns yet another function a → c. And why does this
matter? Because, conceptually, we now have two inputs rather than
three, and because all of a → c, the output we are producing, is in
positive position now.
compose :: (b -> c) -> (a -> b) -> (a -> c)
-------- -------- ++++++++

It this correct? Are we able to produce an a → c? Of course we are,


we already did in \g f a → g (f a). It might be more obvious if we
write it a bit differently, though.

compose :: (b -> c) -> (a -> b) -> (a -> c)


compose = \g f -> (\a -> g (f a))

That rightmost \a → g (f a) has the type a → c.

So which statement about the position of our arguments is correct?


Is a → c positive, or is a negative and c positive? It turns out that
both of these are true, and here we can finally start seeing the utility
of characterizing arguments by their positions. When observed
separately, those a and c have different positions, but when
observed together as part of the same function a → c, said function
itself has a position of its own as well. Let’s try to visualize all this
information.

compose :: (b -> c) -> (a -> b) -> (a -> c)


-------- -------- ++++++++
- +

There, it says that while a → c is in positive position, the a and the c


in it are in negative and positive positions of their own as well.

Let’s look at a → b now, an argument in negative position. What are


the positions of a and b inside this function? Well, seeing how a is
an input in that function, and how b is an output, presumably a is
in negative position and b is in positive position, right? Not quite,
not quite. We are forgetting our point of view, the perspective from
where we are standing. Let’s dig deeper.

From the point of view of compose, the entire function a → b is in


negative position because it’s somehow provided by the caller as
input, and all compose has to do is receive it. We see this clearly in the
implementation, where we bind a → b to the name f.

compose :: (b -> c) -> (a -> b) -> a -> c


compose = \g f a -> g (f a)

The rest of compose's type is saying that eventually we need to


produce a c, and looking at what is available we can see that if we
were able to obtain a b somehow, then we could apply g to that b
and be done. How do we obtain that b? Why, we just apply f to the
a that we have readily available. But look carefully at what’s
happening. From the point of view of f, a is the input it receives, so
it must be in negative position. But it turns out that we don’t care
about f's point of view at all, so let’s ignore what f has to say and
continue searching. The fact that f eventually receives an a at all
implies that there is somebody else applying f to that a, which in
turn implies that whoever calls f needs to produce an a for f to
receive. And who calls f if not compose? So, from the point of view
of compose, when it says f a, that a is in positive position. And this is
despite that a also being in negative position from the point of view
of compose when we bind it in \g f a → …. So, contrary to our
intuition, the a in a → b, from the perspective of compose, is actually
in positive position, for it’s compose itself who is somehow coming
up with an a to which it can apply f, even though that a also
happens to be the one that was originally received by compose.
Generally speaking, the fact that an a appears in negative position
somewhere else in compose's type is irrelevant when determining that
this occurrence of a in a → b is indeed in positive position.

compose :: (b -> c) -> (a -> b) -> (a -> c)


-------- -------- ++++++++
+ - +

And what about parametric polymorphism? Weren’t all as


appearing in a same type supposed to be the same? Why is one a
positive while the other one is negative here? Apples and oranges.
Parametric polymorphism talks about types, and the type a will
indeed be the same throughout. But the position of arguments has
nothing to do with types, it only has to do with who provides for
whom.

So what happens to compose after it applies f a? It receives, in return,


a b. And contrary to our intuition, from the point of view of
compose, the output b of the function a → b is in negative position
because compose is receiving the b that has been provided, returned,
by f.

compose :: (b -> c) -> (a -> b) -> (a -> c)


-------- -------- ++++++++
+ - - +

And once compose receives this b, it can provide it to g, of type b → c,


to finally receive a c in return. This proves that in b → c, from the
point of view of compose, b is an argument in positive position and c
is one in negative position.
compose :: (b -> c) -> (a -> b) -> (a -> c)
-------- -------- ++++++++
+ - + - - +

This is certainly a richer vocabulary for talking about the inputs


and the outputs of our functions. We can say that all the
expressions in negative position are potentially inputs of our
function, and likewise, that all those in positive position are its
outputs.

And for completeness, let’s see what happens if we keep adding


those redundant “conceptual” parentheses to the right.

compose :: (b -> c) -> ((a -> b) -> (a -> c))


-------- ++++++++++++++++++++++
-------- -------- ++++++++
+ - + - - +

Nothing surprising there. We see the same result as we did when we


put some parentheses around a → c before. We are now talking
about compose, the function that given a function of type b → c as
input, returns yet another function of type (a → b) → (a → c) as
output. So, b → c is in negative position, and all of (a → b) → (a → c)
is in positive position. And what about going all the way, and
putting some redundant parentheses around everything?

compose :: ((b -> c) -> ((a -> b) -> (a -> c)))


++++++++++++++++++++++++++++++++++++
-------- ++++++++++++++++++++++
-------- -------- ++++++++
+ - + - - +
Ah, the most absurd example. compose, out of thin air, receiving no
input, produces a value of type (b → c) → ((a → b) → (a → c)). A
value that, thus, must be an argument in positive position. There is
a pattern here, if you care to find it.
68. Covariance
Understanding positions, or rather, developing an intuition for
them, is quite necessary if we expect to excel at what we do. Not so
much because of the matter of positions per se, but because of the
closely related topic of variance, omnipresent in our field.

Let’s continue looking at compose and its positions, but at the same
time, let’s not do it. Let’s stop calling it compose, let’s call it fmap
instead.

fmap :: Functor f => (a -> b) -> f a -> f b

We will add some redundant parentheses around f a → f b to


emphasize what concerns us today. And while we are at it, let’s
leave out the Functor constraint, as we won’t be paying attention to
it for the time being.

fmap :: (a -> b) -> (f a -> f b)

In this light, we can describe fmap as taking a function a → b and


returning a function f a → f b. A type that, when carefully
arranged, reveals an interesting pattern.

fmap :: ( a -> b)
-> (f a -> f b)

Mathematics, ultimately, are in the business of discovering beauty


and structure in change, so finding this type so charming, so
organized, shouldn’t surprise us at all.
What fmap is doing, in other words, is just putting an f around the a
and the b. Well, putting is just a matter of speaking, for we know f a
is an input to fmap, so it’s not fmap but whoever applies it who puts
this f around a. But still, conceptually, we are transforming a
function from a to b, into a function from f a to f b. So much so,
actually, that we often talk about fmap “lifting a function a → b into
f”, rather than “fmapping a function a → b over f a”.

But let’s forget about fmap for a bit and compare these two
functions, a → b and f a → f b, on their own merit. They both have
an a somehow appearing as part of their input, and a b somehow
appearing as part of their output. In other words, directly or not,
the as are part of arguments in negative positions and the bs are part
of arguments in positive ones. That is, despite that f, the positions
of the arguments in a → b is preserved in f a → f b. Lifting a → b
into f didn’t change this. There is a name for this rather
unsurprising phenomenon, it’s covariance.
69. Contravariance
When we say Functor f, we are saying that f is a covariant functor,
which essentially means that for each function a → b, there is a
corresponding function f a → f b that is the result of lifting a → b
into f. The name “covariant”, with the co prefix this time meaning
with or jointly, evokes the idea that as the a in f a varies through a →
b, the entirety of f a varies to f b with it, in the same direction.

But as with many precious things in life, it’s hard to appreciate why
this is important, or at all interesting, until we’ve lost it. So let’s lose
it. Let’s look at this matter from the other side, from its dual, a dual
we find by just flipping arrows. So let’s try that and see what
happens.

contramap :: ( a -> b)
-> (g a <- g b)

A covariant functor f, we said, was one that could lift a function a


→ b into a function f a → f b. So, presumably, the dual of said
covariant functor f —let’s call it “g the contravariant”— is one that
lifts a function a → b into g a ← g b instead, arrow flipped.
Conceptually, this is perfect. In practice, in Haskell, function
arrows always go from left to right →, never from right to left ←, so
we need to take care of that detail. Let’s write the function arrow in
the direction it’s expected, flipping the position of the arguments
instead.

contramap :: ( a -> b)
-> (g b -> g a)
In Haskell, contramap exists as the sole method of the typeclass called
Contravariant, which is like Functor but makes our minds bend.

class Contravariant (g :: Type -> Type) where


contramap :: (a -> b) -> (g b -> g a)

Bend how? Why, pick a g and see. Maybe perhaps? Sure, that’s simple
enough and worked for us before as a Functor.

contramap :: (a -> b) -> (Maybe b -> Maybe a)

Here, contramap is saying that given a way to convert as into bs, we


will be granted a tool for converting Maybe bs into Maybe as. That is,
a lifted function with the positions of its arguments flipped, exactly
what we wanted. Let’s try to implement this by just following the
types, as we’ve done many times before. Let’s write the
Contravariant instance for Maybe.

instance Contravariant Maybe where


contramap = \f yb ->
case yb of
Nothing -> Nothing
Just b -> ‽

A pickle. We know that f is of type a → b, we know that yb is a Maybe


b, and we know that we must return a value of type Maybe a
somehow. Furthermore, we know that a and b could be anything,
for they’ve been universally quantified. There is an implicit ∀ in
there, always remember that. When yb is Nothing, we just return a
new Nothing of the expected type Maybe a. And when yb is Just b?
Why, we die of course, for we need a way to turn that b into an a
that we can put in a new Just, and we have none.

But couldn’t we just return Nothing? It is a perfectly valid expression


of type Maybe a, isn’t it? Well, kind of. It type-checks, sure, but a
vestigial tingling sensation tells us it’s wrong. Or, well, maybe it
doesn’t, but at least we have laws that should help us judge. So let’s
use these laws to understand why this behavior would be
characterized as evil, lest we hurt ourselves later on. Here is the
simplified version of the broken instance we want to check, the one
that always returns Nothing.

instance Contravariant Maybe where


contramap = \_ _ -> Nothing

Like the identity law for fmap, the identity law for contramap says
that contramapping id over some value x should result in that same x.

contramap id x == x

A broken contramap for Maybe that always returns Nothing would


blatantly violate this law. Applying contramap id (Just 5), for
example, would result in Nothing rather than Just 5. This should be
enough proof that ours would be a broken Contravariant instance,
but for completeness, let’s take a look at the second contramap law as
well.

Just like we have a composition law for fmap, we have one for
contramap as well. It says that contramapping the composition of two
functions f and g over some value x should achieve the same as
applying, to that x, the composition of the contramapping of g with
the contramapping of f.
contramap (compose f g)
== compose (contramap g) (contramap f)

Isn’t this the same as the composition law for fmap? Nice try, but
take a closer look.

fmap (compose f g)
== compse (fmap f) (fmap g)

contramap (compose f g)
== compose (contramap g) (contramap f)

Whereas in the case of fmap, the order in which f and g appear at


opposite sides of this equality is the same, it is not the same in the
case of contramap. This shouldn’t come as a big surprise, seeing how
we already knew that contramap gives us a lifted function with its
arguments in the opposite position. Intuitively, dealing with
Contravariant values means we are going to be composing things
backwards. Or, should we say, forwards? After all, compose initially
shocked us with its daring, so-called backwards sense of direction,
and now we are mostly just backpedaling on it.

But the important question is whether our broken Contravariant


instance for Maybe violates this law. And the answer is,
unsurprisingly I hope, not at all. Both sides of this equality always
result in Nothing, so they are indeed equal. Many times they will be
equally wrong, but that doesn’t make them any less equal. And this
is, technically, sufficient for our broken instance to satisfy this law.
Thankfully we had that other law we could break.

So how do we contramap our Maybes? Well, we don’t. As handy as it


would be to have a magical way of going from b to a when all we
know is going from a to b, we just can’t do that. Think how absurd
it would be. If you need some creativity, just imagine a being a tree
and b being fire. So, to sum up, Maybes are covariant functors, as
witnessed by the existence of their Functor instance, but they are not
contravariant functors at all, as witnessed by the impossibility of
coming up with a Contravariant instance for them. So once again,
like in our previous Bifunctor conundrum, we find ourselves
wanting for a function b → a when all we have is a function a → b.
This time, however, we are prepared. We know that we keep ending
up here because we are getting the position of our arguments, the
variance of our functors, wrong. And we will fix that.

Wait. Covariant functors? Contravariant functors? That’s right, both


these things are functors. All that talk we had growing up about
how functors are this or that? A lie. Well, not a lie, but rather, we
hid the fact we were talking only about covariant functors. Now we
know that there are other types of functors too. Unfortunately, the
Haskell nomenclature doesn’t help here. For example, one could
argue that the Functor typeclass should have been called Covariant
instead, or perhaps the Contravariant typeclass should be called
Cofunctor and contramap should be renamed to cofmap, etc. Anyway,
not important. As we continue learning more about functors we’ll
see that even these names fall short of the true nature of functors.
There’s more, yes, and it’s beautiful. But despite their names, both
Contravariant and Functor are typeclasses that describe, indeed,
functors. And it shouldn’t surprise us, considering how we saw in
detail that except for their opposite argument positions, the types
of fmap and contramap, as well as their laws, are exactly the same.
70. Constance
It is high time we learned a new function, and in the most exquisite
tradition of this fine establishment, it will be a boring but beautiful
one.

const :: a -> b -> a

But this time we’ll leave it to you and parametricity to figure out
what const does. Don’t worry, you got this. You’ve been preparing
for this moment all along.
71. Little boxes
Let’s make something very clear once and for all. We said it before,
but here we say it again. Functors —that is, Functors— are not
containers, they are not little boxes.

Functors are type-constructors that are covariant in at least one of its


type parameters and abide by some laws. That’s all. Maybe is a
covariant Functor because in Maybe a, that a shows in positive
position in Maybe's Just, which in turn causes a function a → b to
always be lifted covariantly into Maybe a → Maybe b.

data Maybe a = Nothing | Just a

Can’t see a in a positive light? Let’s look at an example, then.

foo :: Maybe Natural


foo = Just 5

This 5, our a, is being produced here out of the blue. This proves
that a is indeed an argument in positive position from the
perspective of foo. Sure, from the perspective of the Just value-
constructor, the a it expects to receive is certainly in negative
position, but a value-constructor’s perspective doesn’t matter at all
when judging the variance of a datatype. What matters, instead, is
the perspective of the already constructed value. In our case, it’s the
point of view of the Maybe Natural value itself, foo, not the Just
constructor of type Natural → Maybe Natural, what matters.

This truth might be hard to see because we’ve become accustomed


to talking about the position of arguments of a function, yet here
we see no function. Or do we? Think about what a function that
takes no input and returns 5 as output would look like.
Conceptually, no such thing could exist, for inputs are a function’s
raison d’être. No input, no function. So we can’t fathom its looks,
no. But still, without noticing, we just described 5 as the output of
this hypothetical inputless function and had no trouble
understanding what we meant, agreeing on what our goal was. So
it’s our lack of surprise, if you will, what suggests that 5 could in
fact be in positive position.

But suggestions and perspectives are respectively insufficient and


boring, so let’s do something adequate and fun instead. Let’s prove
that an a on its own, just like the one we find inside the Just value-
constructor, is in positive position. We’ll do so by showing how
said a can be represented as b → a instead, a proper function with an
input where it’s blatantly obvious that there is an a in positive
position. And nevermind that b, it could be anything. So how do
we show that a value of one type, here a, can be represented as a
value of a different type, here b → a? Well, generally we just prove
that there is an isomorphism between these two representations.
Unfortunately, while possible, doing so now would derail our
learning process for unrelated reasons, so we’ll just do half of the
work instead. We’ll just show that it is possible to go from a to b →
a, and we’ll leave the conversion from b → a to a for a later day. So,
in concrete terms, we need to implement a function of type a → (b
→ a). Let’s do it.

hola :: a -> (b -> a)

So, hola is a function that given— Wait a minute… Can we drop


those extra parentheses, please? Thanks.
const :: a -> b -> a

Hola indeed! const, we meet again. Let’s write down const's


implementation this time, though, just to be certain we all share the
same understanding.

const :: a -> b -> a


const = \a b -> a

I trust you arrived at the same place during your own exploration of
const. But here it is, in case you didn’t. It’s possible you ended up
with \a _ → a, \a → \b → a, or similar instead. That’s fine, it all
means the same.

So if you dare profit from your innocence and entertain the idea of
an alternative implementation of Maybe, where rather than having a
value of type a we have a function of type b → a in it, there shall be
no doubt whatsoever of the covariance of this datatype.

data Maybe a = Nothing | Just (b -> a)

The experienced reader will notice that, for unrelated reasons, this
Haskell code doesn’t work. But experienced reader, we are just
playing, so let’s pretend it does.

And finally, here is foo again, accommodating the needs of our new
representation.

foo :: Maybe Natural


foo = Just (const 5)
And the b we just made up? Well, who cares? const certainly doesn’t.
It could be anything. As proof of this, let’s implement a function
that adds a 10 to the Natural number contained in one of these
twisted new Maybes, if any.

add_ten :: Maybe Natural -> Natural


add_ten = \yn ->
case yn of
Just f -> 10 + f "potato"
Nothing -> 10

The f inside yn takes anything as input, ignores it, and returns a


Natural number. The ignored thing is our made-up b, the one that
showed up in our fake Just constructor. Here we decided to apply f
to the String "potato", but we could have applied it to id, fmap or
something else instead, and it would have been fine. So, for
example, the expression add_ten (Just 3) equals 13, and add_ten
Nothing equals 10. Of course, as the experienced programmer
noticed, none of this works. That is, however, unimportant, for it
has nothing to do with our current concern and our reasoning
remains nonetheless untainted.

And this same reasoning applies to List, Either and any other
Functor we may encounter. They are not little boxes, they are type-
constructors covariant in the rightmost of their type-parameters,
that’s all they are. The functor instance for functions makes it quite
clear, as the covariance of b in a → b can be seen from far, far away.
72. Profunctor
So what about Bifunctor? Two little boxes, perhaps? No, definitely
not. Let’s recall the definition of the Bifunctor typeclass.

class Bifunctor (f :: Type -> Type -> Type) where


bimap :: (a -> c) -> (b -> d) -> f a b -> f c d

We have so many type variables here that, to the untrained eye, it’s
not obvious what’s going on. So let’s explore this together.
Essentially, bimap is two fmaps in one. We already knew this, of
course, considering how the whole reason for reaching out to
Bifunctor in the first place was that we wanted to act on both the
Left and the Right side of an Either at the same time. So yes,
Bifunctor is two fmaps, two Functors in one. One that turns the a in f
a b into c, and another one that turns the b in it into d. Together,
they turn f a b into f c d.

bimap :: (a -> c) -> (b -> d) -> f a b -> f c d


fmap :: (a -> c) -> f a -> f c
fmap :: (b -> d) -> f b -> f d

Of course, these examples don’t type-check, for none of f a, f b, f c


nor f d are Types. But, if we playfully pretend they are, we’ll see the
resemblance to fmap.

What this implies, among other things, is that the Bifunctor


typeclass expects its f to be covariant in its two type parameters.
And yes, there are some laws that a successful Bifunctor needs to
follow as well. An Either, for example, is covariant in both of its
type parameters: Right has a payload exactly like Maybe's Just, thus
covariant, and the only thing that’s different about Left is its name.
So yes, Either a b is covariant with a and b, which makes it a
suitable Bifunctor candidate. In this regard, a Pair is no different, so
a Pair is also a Bifunctor in principle. But a function? A function is
most definitely not covariant in both its type parameters. Let’s see
why.

First, the easy part. We know that in a → b, a change in b will be


lifted covariantly into the function. That’s what fmap tells us.

fmap :: (b -> c) -> (a -> b) -> (a -> c)

Seeing this in a prefix manner, and with some extra parentheses,


might help.

fmap :: ( b -> c)
-> ((->) a b -> (->) a c)

That is, the unchanging (→) a part is our f here, our Functor. And
we can see how, from the point of view of fmap, all the bs appear as
arguments in negative position and all the cs appear in positive
ones. The implementation of this function proves that functions
are indeed covariant in their outputs. What about their inputs,
though? Well, let’s try to lift a function that changes the a in a → b
into c and see what happens.

foo :: (a -> c) -> (a -> b) -> (c -> b)

This type is similar to fmap's, to compose's, but not quite the same, so
pay careful attention. We’ll call it foo because this function doesn’t
fit in any of the typeclasses we have described so far. We’ll figure
out where to put this code later on. Remember: Here we are trying
to modify the input of a → b, not its output. So let’s try to
implement foo, and let’s also drop those redundant rightmost
parentheses while we are at it.

foo :: (a -> c) -> (a -> b) -> c -> b


foo = \g f c -> ‽

Ugh, trapped again. We have a function that knows how to convert


an a into the b that we need to return, and we have a c, but we have
no way to obtain an a to provide to a → b. Once again we have a
function a → c when what we actually need is c → a. What is going
on? Stop this torture already, please.

Alright, let’s arrange things differently to see more clearly, with


prefix notation, extra parentheses and such.

foo :: ( a -> c )
-> ((->) a b -> (->) c b)

This fool is trying to covariantly lift a function a → c, intended to


modify the input of yet another function, and this can’t happen.
We know this because if we squint hard enough and pretend that
(→) _ b is our Functor —notice the _ hole in there— then what we
are looking at, really, is fmap.

fmap :: ( a -> c)
-> (f a -> f c)

But having failed, repeatedly, to implement this, we know this can’t


ever happen. What if we flip the arrow, then? What if we try to
approach contramap rather than fmap? All we have to do is change the
position of the lifted arguments. That is, rather than ending up
with f a → f c, we should end up with f c → f a.

contramap :: ( a -> c)
-> (f c -> f a)

And now that we have this, let’s replace that f back with (→) _ b
—again, notice the hypothetical placeholder _ in there.

bar :: ( a -> c )
-> ((->) c b -> (->) a b)

We abandoned the name contramap because our type doesn’t fit


contramap's shape anymore. But this is just a superficial issue related
to the fantasy _ placeholder we just mentioned. It has to do with
the fact that we are not focusing on the y in x → y, but rather on the
x. We’ll deal with this later, it’s not a fundamental issue at all. For
now, just pretend bar is contramap. Anyway, let’s make things pretty
again.

bar :: (a -> c) -> (c -> b) -> a -> b

We have an a, we have a way to go from a to c, and also a way to go


from c to b, which is what we ultimately wanted.

bar :: (a -> c) -> (c -> b) -> a -> b


bar = \f g a -> g (f a)

Or, another way of saying this, in a point-free manner:


bar :: (a -> c) -> (c -> b) -> (a -> b)
bar = \f g -> compose g f

That’s right, all we had to do was flip the order of the input
parameters to compose. Anyway, seeing how bar here is essentially
contramap, this proves that functions are contravariant in their
input parameter, the one we were focusing on.

So no, functions are not Bifunctors because they don’t have two
covariant type parameters. They have one covariant parameter, its
output, and another one that is contravariant, its input. Functions
just don’t fit bimap. Notice, however, that Bifunctor is also a terrible
name, because just like how functors, semantically, can be either
covariant or contravariant, the mathematical bifunctor can in
principle have any of its type parameters be covariant or
contravariant as well. Terrible naming indeed. So no, functions are
not Bifunctors in Haskell’s parlance, but they are bifunctors
nonetheless, in the true mathematical sense. Naming mistakes stay
with us forever.

So what does Haskell call a bifunctor that is able to accommodate a


function’s shape, where the first type parameter is contravariant
and the second covariant? Profunctor. Haskell calls it Profunctor.

class Profunctor (p :: Type -> Type -> Type) where


dimap :: (a -> c) -> (b -> d) -> p c b -> p a d

If we compare bimap and dimap side by side, we’ll see they are
essentially the same, except the as and cs appear in opposite
positions.
bimap :: (a -> c) -> (b -> d) -> p a b -> p c d
dimap :: (a -> c) -> (b -> d) -> p c b -> p a d

The Profunctor instance for functions should be unsurprising. The


trickiest part is seeing how our function type-constructor (→)
becomes that p. First we replace p with (→):

dimap :: (a -> c) -> (b -> d) -> (->) c b -> (->) a d

And then we move those prefix (→) type-constructors to an infix


position, adding some parentheses as necessary.

dimap :: (a -> c) -> (b -> d) -> (c -> b) -> (a -> d)

Beautiful. Although, let’s remember that the rightmost parentheses


are optional. Let’s get rid of them, actually.

dimap :: (a -> c) -> (b -> d) -> (c -> b) -> a -> d

So now dimap can be described as the function that given an a, a way


to obtain a c from that a, a way to turn that c into a b, and finally a
way to convert that b into a d, returns said d.

instance Profunctor (->) where


dimap = \f h g a -> h (g (f a))

Intuitively, dimap f h g a, where we’ve conveniently named f, g and


h alphabetically, applies f, g and h to a, in that order. It’s customary,
however, to disregard that a and, in a higher-order point-free
fashion, focus solely on the composition of f, g and h.
dimap = \pre pos g -> compose pos (compose g pre)

This time we chose names pre and pos, rather than f and h, to
highlight that the application of pre precedes the application g —our
Profunctor, the function we are transforming— and that the
application of pos is posterior to it. This is quite a common
nomenclature. Of course, we could have composed pos and g first,
and only then composed this with pre, as in compose (compose pos g)
pre. It’s all the same, for even if we haven’t said so explicitly,
function composition is associative.

So that’s it. Functions are indeed bifunctors, yes, but the Profunctor
kind, where their first type-parameter is contravariant and only the
second is covariant.
73. Opa
We know that a function a → b is contravariant in a, yet we have
neglected writing a Contravariant instance for it. Let’s fix that.

It turns out that, in Haskell, saying that a → b is contravariant in a is


not quite straightforward for a very superficial, boring reason.
That’s why we have neglected this so far. We assumed in the
previous chapter that our contravariant functor was (→) _ x, with
that _ hole in it, but there’s just no way to write that holey thing in
Haskell, so we need some gymnastics to shoehorn (→) _ x into
place. The main issue is the same we had with the Functor instance
for Either, where we could only ever fmap over the Right because
Functor expected a type-constructor kinded Type → Type as its f, and
only Either x, with a fixed x on the Left, had that kind. In the case
of functions, (→) x has that kind too, but the problem is that (→) x
is fixing its contravariant parameter, the one contravariance
ultimately cares about, to always be x, which ultimately defeats the
whole purpose of contramap.

Ideally, what we would like to do is say that (←) x, arrow flipped, is


an instance of Contravariant where the x that has been fixed is the
output, rather than the input of the function, leaving the
contravariant parameter free for our mischiefs.

instance Contravariant ((<-) x) where


contramap = \f g a -> g (f a)

In this case, contramap would take the type (a → b) → (x ← b) → (x ←


a) and all would be right in the world. However, we learned, there
is no such thing as an arrow going from right to left ← in Haskell, so
this won’t work. Yet, we have something quite close.
data Op b a = Op (a -> b)

The Op datatype, standing for opposite, is essentially our flipped


arrow ←. It’s just a wrapper around a normal function with arguably
uglier looks. In both Op b a and a → b we have a covariant b and a
contravariant a, they just show up in opposite order as type-
parameters. Other than there being a function inside Op, nothing
here is new. We did the same thing a while ago with a datatype
called Flip that flipped the sides of an Either.

data Flip b a = Flip (Either a b)

Look, Flip and Op are essentially the same. It’s only their names and
the type they wrap what changes.

data Op b a = Op ((->) a b)
data Flip b a = Flip (Either a b)

Anyway, the important thing is that we can finally give functions a


Contravariant instance through Op.

instance Contravariant (Op x) where


contramap = \f (Op g) -> Op (\a -> g (f a))

The implementation is a bit noisy because once Op x is chosen as


our Contravariant functor, the type of contramap becomes (a → b) →
Op x b → Op x a, which means we need to pattern match on the Op
constructor to extract the b → x function inside Op x b, and later
apply the Op constructor to the function that will finally receive and
transform the a, so that said function becomes Op's payload. But, if
you put Op's contramap side by side with the wishful contramap for our
fantasy leftwards arrow (←), you’ll see this in a more familiar light.

contramap = \f g a -> g (f a)
contramap = \f (Op g) -> Op (\a -> g (f a))

The Op stuff is just contortions to make Haskell happy. But in


principle, we were right all along. We’ll see more contravariant
functors later on.
74. Profunity
But why do we care about functors, variance and profunctors so
much? I mean, it took us forever to get here, so it better means
something.

The beauty of Profunctor is that it generalizes the idea of a program


beyond just functions. Suddenly, anything that has inputs and
outputs can be manipulated, and that is beautiful.

dimap :: Profunctor p
=> (a -> c) -> (b -> d) -> p c b -> p a d

The type of dimap is saying that we can change any p that is a


Profunctor —that is, any p that is somehow a program— so that it
accepts any a rather than any c as input, and produces any d rather
than any b as output. Any.

Moreover, we can do this in a predictable manner because the


Profunctor typeclass has laws making this whole thing a transparent
and trustless endeavour. Well, in the most beautiful anarchic sense
anyway, for there’s no police to enforce such laws. We are talking
about the usual functor laws, of course. After all, a Profunctor is just
two functors in one. So we have an identity law and a composition
law expected to be satisfied by every Profunctor instance.

dimap id id == id

dimap (compose f g) (compose h i)


== compose (dimap g h) (compose f i)

So what other things are Profunctor, beside functions? Ah, wouldn’t


we like to know… We’ll have to wait, though, I am afraid, for we
moved so fast that we’ve run out of problems to solve. Suffice it to
say that not only have we decoupled ourselves from the computer,
the machine, but we’ve also parted ways with the function which,
we were told, was everything there was. We are free now.
75. Mundane
So far, in this book, we have mostly learned about how to use types
to reason about our problems. Everything we learned was
important and fundamental somehow, and ultimately, has helped
us develop the mindset and principles we need. But unfortunately,
we don’t have much to show for it yet. There’s nothing mundane,
nothing we can touch. There’s so much we know, yet we can barely
write a program that does something. So let’s fix that now, let’s
write some earthly programs.

sum :: [Natural] -> Natural


sum = \xs ->
case xs of
[] -> 0
x : rest -> x + (sum rest)

This function, sum, adds together all of the Natural numbers present
in a list. The type of sum doesn’t say much, but if we look at the
implementation of this function we will see that it recursively adds
each element in the list. For example, applying sum to [2, 4, 3]
would result in 9, for it reduces to 2 + sum [4, 3], which further
reduces to 2 + (4 + sum [3]) and then to 2 + (4 + (3 + sum []))
before finally becoming 2 + (4 + (3 + 0)). If we add those numbers
together, we end up with 9.

Returning 0 when we encounter an empty list [] makes sense if we


consider that adding nothing together would result in, well,
nothing, an idea often conveyed by 0.

And what about multiplying numbers together instead? Let’s do


that as well.
product :: [Natural] -> Natural
product = \xs ->
case xs of
[] -> 1
x : rest -> x * (product rest)

product is quite similar to sum. All that changes is that we now


multiply numbers with * rather than adding them with +, and that
in the case of an empty list [] we return 1 rather than 0. The rest of
this function is exactly the same as it was in sum. These new choices
mean that, for example, product [2, 4, 3] will result in 24, for it
reduces to 2 * product [4, 3] first, which then becomes 2 * (4 *
product [3]), further reducing to 2 * (4 * (3 * product [])) to
finally become 2 * (4 * (3 * 1)), which according to our calculator
is 24. Those are really handy machines, use them.

The funny thing is the 1 there. It was easy to make sense of 0 in the
case of sum because of its relation with the absence of things. If we
have no numbers to add, we get 0 as result. Quite reasonable.
However, in product we are saying that if we have no numbers to
multiply, then we get 1 as result. Where does the 1 come from, if we
have nothing to multiply at all? It is a bit funny, yes, I’ll give you
that. Yet, multiplying 2 * (4 * (3 * 1)) together really leads us to
24, which according to the abacus is exactly the number we expect
as the result of multiplying all of 2, 4 and 3 together. So where’s the
trick? What’s going on?

Seldom do we programmers, we mathematicians, care about things


in isolation. It’s in their relationships, in their belonging, that we
find meaning. 0 is not interesting because of its familiar sense of
absence, but because adding it to another number results again in
that same number. 7 is 7, but 7 + 0 is also 7. It’s in the relationship
that 0 has with other numbers through addition that we find
meaning. And the same is true for 1, which when multiplied by any
other number results in that number once again. 7 is 7, but 7 * 1 is
also 7. So close your eyes now, take a deep breath and look deeper.
What do you see?

Identity, darling, you are everywhere. You never leave, you never
cease to amaze us. Yes, yes indeed, adding zero or multiplying by
one are identities as well. We can write a function that adds zero,
another that multiplies by one, call them id, and it would be alright.
However, this time things are a bit different, and we are looking for
something else. For one, we are assuming that the input to our
identity function will be some kind of number, for we should be
able to multiply it or add to it at times. This alone already violates
the parametric polymorphism in ∀ x. x → x, which says nothing
about x, let alone it being a number. But beside this, we need to
understand that it’s not 1 nor 0 who are the identities, but instead,
it’s the combination of one these numbers with a particular
operation, here * and +, who are. So much so, actually, that as every
other interesting thing in our journey, these numbers have special
names. We say 0 is the additive identity and 1 is the multiplicative
identity. We sometimes call them the units or identity elements of
their respective operations, too. So no, we can’t really separate 0
from +, nor 1 from *, if we want to keep calling them identities.

But perhaps more importantly, at least insofar as sum and product are
concerned, we need to acknowledge that being able to add and
multiply numbers is necessary, notwithstanding whether these
numbers are identity elements or not. When we arrived to 2 * (4 *
(3 * 1)), for example, we were using * to multiply many numbers
beside just 1, and that was fine. That is, while we certainly have a
motivation for keeping the concepts of 1 and * together so that we
can speak of them as an identity, we also have a motivation for
keeping them separate, so that we can use * without involving 1 at
times. In other words, we need to pair 1 and * without conflating
them. So from now on, conceptually at least, we will pair elements
with the operation for which they behave as identities, so that we
are able to use them together or separately as we see fit. And these
pairs, being as interesting as they are, will have a name too. We will
call them monoids. We will explore them in detail later on, but for
now let’s just remember their name monoid and what it means.

Interestingly, what told sum and product apart brought them closer
together as well, furthering our thesis that nothing mundane is as
special as we are made to believe. The different behaviors of sum and
product are simply due to their conscious choice of one of these
monoids. But this is only half of the truth, of course, for if we leave
monoids aside for a moment, the rest of sum and product are exactly
the same, which should immediately catch our attention as
something special too. So let’s abstract away what’s unique about
sum and product, focusing on what’s not.

foldr
:: (Natural -> Natural -> Natural)
-> Natural
-> [Natural]
-> Natural
foldr = \op unit xs ->
case xs of
[] -> unit
x : rest -> op x (foldr op unit rest)

Things got a bit hairy. We’ll clean this up soon enough, don’t
worry, but for now let’s try to follow along. Fundamentally, only
two things changed between product, sum and this new function
foldr. Whereas before we mentioned 1 or 0 directly, respectively
hardcoded inside the definitions of product and sum, here we are
making it possible to receive this value as an input to this function.
Its name, unit, should remind us of its purpose. Furthermore, we
also abstract away the operation we perform on these numbers. We
call it op, and it occupies the place that * and + did before. This time
op appears in a prefix position, but that’s a cosmetic matter that
shouldn’t surprise us: We know that a + b, say, is the same as (+) a
b, so if (+) ever becomes that op, it will be alright.

The types that unit and op take can be inferred from their use, so
don’t let that scare you. First, let’s keep in mind that foldr
ultimately returns a value of type Natural. It says so in the tin. And,
since unit is the value foldr will return when we encounter an
empty list [], then unit must necessarily be of type Natural too. We
use a similar reasoning for inferring the type of op, which we see
being applied to two arguments. The first of these arguments, x, is
an element found inside a list of Natural numbers, so it must be a
value of type Natural itself. The second argument to op is the result
of a recursive call to foldr which, we just said, results in a value of
type Natural. And finally, not only must op take two Natural
numbers as input, but it must also return yet another Natural,
because like in unit's case, the return type of foldr mandates that
the expression foldr returns always be Natural. And that’s it. We
have concluded that x must be of type Natural and op must be of
type Natural → Natural → Natural, so these are the types of the
expressions we see foldr take as new inputs, beside the actual list of
Natural numbers to process.

With foldr in place, we can now redefine sum and product in a more
concise and fundamental way by partially applying foldr, the
function that somehow knows about the structure of a list, to the
operations and units of the monoids that know how to combine
the elements in that list.

sum :: [Natural] -> Natural


sum = foldr (+) 0

product :: [Natural] -> Natural


product = foldr (*) 1

So we found a new thing, foldr, that in a manner similar to fmap


allows us to operate on lists for different purposes without
repeating ourselves each time. And then we found those monoids
too, which are somehow the essence of our programs. There’s
clearly something beautiful going on here.
76. Origami
foldr is what we call the right fold of a list, and it is, essentially, a
function that allows us to transform a list into almost anything else
we can make out of its contents. If we recall, a list of values of type a
can be either empty, as witnessed by the “nil” constructor [], or it
can contain at least one value of said type a preceding the rest of the
list, as witnessed by the “cons” constructor (:) which we usually
use in infix form as a : rest. In order to construct a list, we must
use these constructors somehow.

foldr is exactly the opposite. We could say that foldr is how we


destruct a list, actually, and it would be fine. Think about how foldr
op unit will use unit whenever it encounters [], and how it will use
op on both a and rest whenever it encounters a : rest. A list that
was constructed with [] will be “destructed” by foldr op unit by
replacing [] with unit, and one that was constructed as a : rest will
have this application of (:) to a and rest replaced by op a (foldr op
unit rest). And since [], (:) and those as are all there is to lists, we
can say that foldr is effectively touching everyting in the list,
transforming it as it goes.

It might be easier to appreciate this visually, so let’s try that. We said


that sum [2, 4, 3] resulted in 2 + (4 + (3 + 0)), and in the past we
also said that [2, 4, 3] could be written as 2 : (4 : (3 : [])). Let’s
put those two side by side and see what happens.

2 + (4 + (3 + 0))
2 : (4 : (3 : []))

Astonishing. Our unit, which in the case of sum is 0, is replacing the


occurrence of [] in our list. And our op, which in this case is (+), is
replacing every application of (:). In other words, conceptually,
foldr is allowing us to go back in time to the moment when the list
was constructed, and use the elements in that list, in the same order,
to accomplish something other than creating a list. Quite beautiful,
isn’t it?

And at this point, curious as we are, we should stop and wonder


what would happen if we pick [] to be our unit and (:) to be our
op. Well, we don’t need to do much thinking to figure it out, do
we? We would be replacing every occurrence of [] with [], and
every occurrence of (:) with (:). In other words, everything would
stay the same, nothing would change. What do we call that?

id :: [a] -> [a]


id = foldr (:) []

That’s right, we can define the identity function for lists using foldr
too. We said before that we could use foldr to convert lists into
more or less anything we wanted, which suggests that it should be
possible to convert them to themselves too, and our definition of id
here is the proof of that. However, when we introduced foldr
before, we did it in a context where we wanted to multiply and add
numbers, so we focused on lists containing Natural numbers and on
ultimately returning Natural numbers as well, so we can’t really
implement this id function with it. But all that Natural selection
was unnecessary, and we could have made foldr a bit more
polymorphic instead.
foldr :: ∀ a z. (a -> z -> z) -> z -> [a] -> z
foldr = \op unit xs ->
case xs of
[] -> unit
x : rest -> op x (foldr op unit rest)

The implementation of foldr is exactly the same as before. All that’s


changed here is that instead of talking about Naturals in its type, we
now talk about as and zs. Let’s justify these choices. First, notice
how a and z have been universally quantified separately, meaning
that they could be any type, possibly different from each other.
Second, notice how ultimately we are expecting to return a value of
type z. Now, since the two things we ever return are our unit or a
fully applied op, then both unit and the return value of op must have
type z too.

foldr :: ∀ a z. (_ -> _ -> z) -> z -> [_] -> z

Then, we said that the elements in our list are of some type a, and
the only place we ever deal with these elements directly is in our call
to op, where an a is its first parameter.

foldr :: ∀ a z. (a -> _ -> z) -> z -> [a] -> z

The only thing remaining is the second parameter to op. But this is
rather easy, too, since we can see how this parameter is a full
application of op, which we already know returns a value of type z.
So z it is.

foldr :: ∀ a z. (a -> z -> z) -> z -> [a] -> z


From as to z, this is where we wanted to be. And this new
polymorphism, among other things, allows us to pick (:) of type a
→ [a] → [a] to be our op, and [] of type [a] to be our z, to finally
have a foldr (:) [] of type [a] → [a].

Folds, with their origami name reminding us that we are just giving
a different shape to all the material present in a datatype, are the
higher-order functions through which we can transform a datatype
in its entirety to something else of our own choice. That’s it.

But we talked about foldr being the right fold of a list, right? Yes we
did, and intuitively, that means that when we write something like
foldr (+) 0 [2, 4, 3], we end up with 2 + (4 + (3 + 0)), where the
parentheses seem to be accumulating to the right side of this
expression. But this is not the only way to fold a list, no. For
example, we also have the left fold of a list, which we call foldl, and
intuitively, accumulates parentheses on the left. That is, foldl (+) 0
[2, 4, 3] would result in ((2 + 4) + 3) + 0. Now, this difference is
not particularly important if we are trying to add our numbers
together, because whether the parentheses are to the left or to the
right doesn’t matter at all to our addition operator +. Both 2 + (4 +
(3 + 0)) and ((2 + 4) + 3) + 0, if we try them in our calculator, will
result in 9. However, many other times it does matter. For example,
when we try to use [] and (:) as our unit and op. In this case, foldl
(:) [] would in theory result in ((2 : 4) : 3) : []. However, that’s
nonsense that doesn’t even type-check. Think about it. When we
say 2 : 4, for example, we are trying to apply the (:) to two values
of type Natural. But we know that if the first input parameter to (:)
is a Natural, then the second must necessarily be a list of them, of
type [Natural]. So this just fails to type-check, meaning that our
choice of foldl vs foldr matters here.
The reason why + and * succeed here is that they are associative
operators, whereas (:) is not. We saw this before, but just as a
reminder: A function f is associative if f a (f b c) and f (f a b) c
are equal. Or, arranging things in an infix manner as in the case of
+, we say that an operator + is associative if a + (b + c) equals (a +
b) + c. The “cons” operator (:) is not associative, because a : (b :
c) is not equal to (a : b) : c. Actually, this last example doesn’t
even type-check, so any discussion about associativity or equality is
moot.

Anyway, associativity doesn’t have much to do with folding, so let’s


just proceed to contemplate the implementation of foldl, the left
fold of a list.

foldl :: (z -> a -> z) -> z -> [a] -> z


foldl = \op unit xs ->
case xs of
[] -> unit
a : rest -> foldl op (op unit a) rest

Let’s compare the types of foldr and foldl first.

foldr :: (a -> z -> z) -> z -> [a] -> z


foldl :: (z -> a -> z) -> z -> [a] -> z

The only difference between their types is in the first parameter to


these functions, op, which in foldr takes the element of the list, of
type a, as its first argument, whereas in foldl it takes it as its second
argument.

The actual implementation of foldl is a bit trickier than that of


foldr. This time, when faced with a : rest, foldl recursively calls
itself as foldl op (op unit a) rest instead. That is, foldl is calling
itself with op unit a as a new unit. Let’s try to understand what’s
going on, because this is a bit surprising. Let’s look at what the
execution of foldl (+) 0 [2, 4, 3] looks like, step by step. That
should clarify things for us.

First, foldl (+) 0 [2, 4, 3] reduces to foldl (+) (0 + 2) [4, 3].


This application then reduces to foldl (+) ((0 + 2) + 4) [3], which
further reduces to foldl (+) (((0 + 2) + 4) + 3) [], finally
returning all of ((0 + 2) + 4) + 3, all of unit, as its output.
Technically, this is a beautiful execution of our fold. Semantically,
though, we find ourselves in a bit of a pickle. Suddenly, expressions
like 0 + 2 or ((0 + 2) + 4) + 4 are taking the place of unit as we
recurse into a next call to foldl. And while computers don’t care
about our name choices, we humans most certainly do: These
things are not the unit, the identity element of our monoid,
anymore. What’s going on?

Lies. What’s happening to the units of our foldl are lies. Well, kind
of. When we introduced foldr, the relationship between its unit and
the idea of the identity element of a monoid was so obvious, that
we decided to profit from this accident by taking the opportunity
to explore it. You see, monoids are important, they bring clarity to
everything they touch, and luckily for us they touch many, many
things. And yes, we’ll divert our attention to a monoid whenever
we see one, and we’ll see quite a few of them. So get used to the
idea, profit from it, and learn to recognize those monoids. But no,
monoids and folds don’t have much to do with each other after all.
In fact, to give a concrete example, (:) and [] are not a monoid, yet
we were able to foldr (:) [] just fine. So let’s refine our perspective
to understand the truth that’s unfolding here.
77. Accumulate
Folding lists abstracts the idea of iterating over their elements.
Rather than rewriting all the recursive machinery each time we
need to transform a list, here we have some higher-order order
functions that will do the boring bits for us. And we don’t tackle
the entire list at once. Instead, we address the elements of the list
one by one. This allows us to focus, at each step, only on what is
important. But we don’t do this in isolation, no. If we did, we
would be looking at something more like fmap, which allowed us to
treat each element of our list oblivious of that element’s relationship
to the rest of the list. That’s not a bad thing, though. Not knowing,
actually, is what we love about fmap and functors. But folds are
different, the are a more nosy, neighbourly abstraction. Let’s take a
look at foldr again.

foldr :: (a -> z -> z) -> z -> [a] -> z


foldr = \op acc xs ->
case xs of
[] -> acc
a : rest -> op a (foldr op acc rest)

We renamed our unit parameter. We are calling it acc this time,


short for accumulator. The intuition here is that foldr, as it goes
about its origami business, accumulates in this acc what will
eventually become the output of the whole execution of foldr. We
see this situation, explicitly, when we find ourselves returning acc
once we arrive to [], the end of our list. Or the beginning,
depending on the perspective you take. And it’s actually these
different perspectives what tell foldl and foldr apart.

When we construct a list using [] and (:), we tend to say that we


start from an empty list [], and we build on top of this humble
beginning by adding more and more elements to it using “cons”
(:). Eventually, we end up with a list of things we care about. This
is the same perspective that foldr takes. foldr considers [] to be the
beginning of the list, so that’s where it starts working. It’s easy to
see this if we recall how we were taught in elementary school, in
arithmetic, how we are supposed to tackle the things inside
parentheses first. If we see 3 * (5 + 7), for example, we know the
addition of 5 and 7 must happen before the multiplication by 3.
The parentheses say so, that’s their whole purpose. Well, look at at
what the output of foldr (+) 0 (2 : (4 : (3 : ([])))) looks like,
this time with many redundant but still sensible parentheses. That
is, look at 2 + (4 + (3 + (0))). The parentheses lean themselves to
the right, they are deeper where [] was in our input list, and
ultimately suggest that the elements that are closer to [] will be
processed first.

Let’s try and follow the execution of foldr step by step, and let’s
reduce any expresions that can be reduced, such as 5 + 1 into 6, as
soon as we encounter them. As a high-level overview, here goes a list
of all the reduction steps in this expression, written line by line, so
that we can more easily visualize how we get from foldr (+) 0 [2,
4, 3] to 9.

foldr (+) 0 [2, 4, 3]


== 2 + (foldr (+) 0 [4, 3])
== 2 + (4 + (foldr (+) 0 [3]))
== 2 + (4 + (3 + (foldr (+) 0 [])))
== 2 + (4 + (3 + 0))
== 2 + (4 + 3)
== 2 + 7
== 9
As before, we start from foldr (+) 0 [2, 4, 3]. On a first iteration,
as we process that leftmost 2, this will reduce to 2 + (foldr (+) 0
[4, 3]). Unfortunately, we can’t really know the number that
results from adding 2 to foldr (+) 0 [4, 3] just yet, for we won’t
know the numerical value of foldr (+) 0 [4, 3] until we reduce it
further. So let’s reduce it. foldr (+) 0 [4, 3] becomes 4 + (foldr
(+) 0 [3]), and once again we have a number, 4, which can’t be
added just yet because we won’t know the numerical value of the
other operand, foldr (+) 0 [3], until we reduce it. So let’s reduce it.
We end up with 3 + (foldr (+) 0 []) this time, yet another
addition we can’t perfom until we reduce foldr (+) 0 []. So we do,
we reduce it, and finally get our hands in the rightmost numerical
value in our fold, the deepest one inside our parentheses, 0, born
out of the beginning of our list, [], out of “nil”, out of nothing. But
don’t forget that 0 was the number we’ve been passing as input to
foldr all along, so there’s no magic going on here. To sum up, we
have gone all the way from 2 + (4 + (3 + (foldr (+) 0 []))) to 2 +
(4 + (3 + 0)) now. And this is boring, I know. Yawn through.

Alright, we have numbers now, so what do we do? Why, we finally


start adding them, of course. We worked so much to get here, to
this so-called “beginning” of the list, yet so far we haven’t been able
to perform any of the additions we wanted. We have all of 2, 4 and 3
waiting to add themselves to something. So let’s start from what’s
closest to 0, to the inner parentheses. We had 3 + (foldr (+) 0 [])
which we couldn’t perform until we had a numerical value for
foldr (+) 0 [], but now we do, it’s 0, so let’s tackle 3 + 0. Ok, we
know this is 3, but let’s not be so quick about it, let’s try to
understand what’s going on. Remember, (+) here is what we called
op at some point, and we said that op took two parameters as input.
The first one being the list element that concerns us, which in our
case is 3, and the second being the accumulated return value so far.
Accumulated how? What does this mean?

Let’s remind ourselves that we are looking at this particular scenario


from the perspective of 3 now, from within the context of a
constructor (:) being applied to this 3 and the rest of the list too,
which in this case is the empty list []. And rest is the only part of
our list for wich we were able to obtain any kind of numerical value
so far, 0, by applying foldr to the same arguments (+) and 0. That is,
0 is part of our folding result somehow. But this result is not
sufficient, for we still need to deal with the other elements in the
list. So foldr just accumulates this intermediate result for the time
being, and expects that somebody else improves it later on by
somehow combining it with the other elements in our list. And
who’s the one doing the improving? It’s op of course, by which we
mean (+) in our case. op takes the current element being tackled as
its first parameter and the accumulated result to be improved as its
second argument. The type of op in foldr is a → z → z, where a is the
type of each element inside the list we are folding and z is the type
of foldr's output altogether, recursively being fed to op so that it can
be improved into a new z that somehow takes this a into account
too. Improved how? Well, in our case, we just add the element in
the list we are currently looking at, 3, to the result accumulated so
far. And that’s it, that’s our “improvement”. Now all of 3 : [] has
been right-folded into 3. We have gone from 2 + (4 + (3 + 0)) to 2
+ (4 + 3). And look at how the rightmost inner parentheses are
gone too, enabling us to go back to adding that 4 that we couldn’t
add before.

And now we do the same process all over again, but this time
focusing on 4, and with 3 rather than 0 as the initial value of our
accumulator. op, that is (+), is looking at the number 4 within the
context of 4 : rest, and it knows that the parameters it’s getting as
inputs are 4 itself and the accumulated result of right-folding that
rest, which we just said is 3. All (+) needs to do now is improve this
result somehow, which, as before, it does by adding the element
and the accumulated result togeter. So 2 + (4 + 3) becomes 2 + 7,
and finally we do the same once again to improve 7, the result of
right-folding 4 : (3 : []), by adding it together to the leftmost
element of our list, 2, who has been waiting for us to finish this trip
all along. Incredibly patient, that 2. And at last, we arrive to our
longed numerical result, 9.

For comparison, here’s how a reduction using foldl, rather than


foldr, would happen.

foldl (+) 0 [2, 4, 3]


== foldl (+) (0 + 2) [4, 3]
== foldl (+) (2 + 4) [3]
== foldl (+) (6 + 3) []
== 9

foldr saw [] as the beginnig of the list, which caused it to recurse its
way from [2, 4, 3] to [] so that it could finally start operating on
those list elements, starting from the rightmost 3, with the
accumulator always being the rightmost input to op. But foldl, on
the contrary, sees the list’s most recently added element as its
beginning, so it can start operating on lists elements right away,
recursing with the accumulator as the leftmost input to op until the
list has been exhausted, at which point the result accumulated so far
is simply returned.

The result is the same 9 in both cases. foldr, however, did much
more work to get there. Twice as much. So why would we ever use
foldr? Well, for two reasons. First, because whenever op is not an
associative operation, the results will definitely not be the same. We
witnessed this when we picked the non-associative (:) as our
operator. And, somewhat tangential, do you remember that thing
we said about monoids bringing clarity to everything they touch?
Well, this is another situation where they do. The operation of a
monoid, like + or *, is always associative. There is no such thing as a
monoid whose operation is not associative, which, at least for
semantic purposes, takes the weight of picking between foldl and
foldr off our shoulders. And second, foldr is necessary because it
allows us to work with infinitely long lists, whereas foldl just can’t
cope with that. That’s right. We haven’t seen this yet, but Haskell
has no problem at all in representing infinitely large datatypes, and
by means of foldr we can operate on them within a finite amount
of time and space. Yes, Haskell can do that.

What a ride. What a boring ride. Good thing we almost never have
to follow through the execution of a program this way. This is the
kind of stuff we let computers and type-checkers do for us. What
matters is understanding the ideas and interesting concepts such as
folding, developing an intuition for them, and learning how to
tickle the computer in the right place so that it’ll do them for us.
Our ultimate goal is for our knowledge and skills to become latent,
for that’s how we get to spend time worrying about the important
things instead. There will come a time in our journey when we
won’t need to worry about details unless we really want to. We will
have decoupled meaning from execution, it will be our reward.
78. Pancake
Here’s another function for you to think about and implement on
your own. And try to come up with a less distracting name for it, it
will help.

pancake :: (a -> b -> c) -> (b -> a -> c)


79. Stack
Picture yourself facing a table with three plates on it, each one on
top of another. The black plate is on top of the table, the red plate
is on top of the black one, and the white plate is on top of the red.
Table, black, red, white. Without being too clever nor showcasing
any charming magician skills, how would you proceed if you
wanted to rearrange this pile of plates so that the black plate is on
top of the red, and the red on top of the white instead? You can
only move one plate at a time.

We take the white plate, the one most recently added to the pile,
and put it on the side. Now we have two piles of plates, rather than
one. There’s one with a red plate on top of a black plate, and
another one with just a white plate. Next, we grab the red plate and
put it on top of the white plate. Now we have a pile with the red
plate on top of the white, and the original pile with just the black
plate left in it. Finally, we take this black plate and put it on top of
the red one. Now the original pile is empty, and the new pile has
black on top of red, on top of white. We have reversed the order of
the plates.

Linked lists are like these piles of plates. Or worse, perhaps. Imagine
you can only look at this pile from above, so all you see is the plate
at the top of the pile, the one that was added to it more recently,
and you can’t tell how many plates are below it. Maybe there’s one,
maybe there are none, or maybe there’s infinitely many of them.
You can’t see what’s beneath the last added plate without first
taking it out of the pile. Last in, first out. That’s what linked lists
are.

In programming, we call structures like the linked list, which have


this last in, first out property, “stacks”. They behave like a pile, like
a stack, of plates. That’s why foldr, who insists on seeing [] as the
first element of a list, often does twice as much work as foldl. It
needs to move past all the plates, one by one, before doing any real
work. Well, kind of. We will soon find this to be a lie too. But for
now, it is our truth.
80. Reverse
Alright, let’s fold some. Let’s see if we can reverse the order of the
elements in a list, the order of the plates in our pile, using some
kind of fold. That is, let’s see if we can turn [1, 2, 3] into [3, 2, 1]
somehow. This could come handy, say, if we were running a plate
business.

Like we learned, we achieve this by taking the plate that’s at the top
of the stack, the leftmost element of our list, and putting it on top
of the new pile we are building instead. In Haskell parlance, the list
we are building is our accumulator, and the leftmost element is the
element to which foldl applies its accumulating function. So let’s
write that accumulating function for foldl, let’s have it put the
element on top of the accumulated list.

reverse :: [a] -> [a]


reverse = foldl (\acc a -> a : acc) []

That’s it. Yes, reverse does the trick. Here’s how the reduction of
reverse [1, 2, 3] happens, written using the verbose infix
constructor : to make a point.

reverse (1 : (2 : (3 : [])))
== foldl (\acc a -> a : acc) [] (1 : (2 : (3 : [])))
== foldl (\acc a -> a : acc) (1 : []) (2 : (3 : []))
== foldl (\acc a -> a : acc) (2 : (1 : [])) (3 : [])
== foldl (\acc a -> a : acc) (3 : (2 : (1 : []))) []
== 3 : (2 : (1 : []))

Elements flock from the input pile to the new pile acc as we peel,
one by one, the “cons” constructors (:). And, in case you didn’t
notice, \acc a → a : acc is just flipping the order of the input
parameters to (:). If you think of (:) as a function of type a → [a] →
[a], then \acc a → a : acc is a function of type [a] → a → [a]. All
that’s happening in our chosen op is that the order of input
parameters to (:) are being flipped. Does this remind you of
something?

flip :: (a -> b -> c) -> (b -> a -> c)


flip = \f b a -> f a b

flip is a handy higher-order function we use quite often to achieve


the same \acc a → a : acc does, in a cleaner and more reusable
package. Rather than saying \acc a → a : acc, we can say flip (:).
It’s the same. Go ahead, prove that this is true using equational
reasoning if you have doubts. We called this pancake before. And
with this, we can define reverse as foldl (flip (:)) [] instead.
Here’s the same reduction as before, written differently just for
show.

reverse [1, 2, 3]
== foldl (flip (:)) [] [1, 2, 3]
== foldl (flip (:)) [1] [2, 3]
== foldl (flip (:)) [2, 1] [3]
== foldl (flip (:)) [3, 2, 1] []
== [3, 2, 1]

An interesting property of reverse is that reversing the same list


twice gives back the same list. Try it with the plates on your table,
touch the identity, you’ll see.

xs == reverse (reverse xs)


Or, as we often say:

id == compose reverse reverse


81. Concat
Something else we’ll often want to do is concatenate lists together.
Say I have [1, 2] and you have [3, 4]. Concatenating these lists
together should result in [1, 2, 3, 4]. Let’s see if we can solve this
using folds. After all, we were told we could fold our way into
almost anything, so this should be possible too. We want to
implement a function named concat of type [a] → [a] → [a], short
for “concatenate”, where among other examples, concat [1, 2] [3,
4] results in [1, 2, 3, 4].

concat [1, 2] [3, 4] == [1, 2, 3, 4]

But let’s write this using (:) and [] instead, adding superfluous
parentheses and arranging things differently so that Prägnanz can
do its thing.

concat (1 : (2 : ([] )))


(3 : (4 : []))

== (1 : (2 : (3 : (4 : []))))

That’s right. All that concat is doing is replacing the [] in its first
argument, 1 : (2 : ([])) with the entirety of its second argument 3
: (4 : ([])). Everything else stays the same, all we do is replace [].

Replace [], replace [], couldn’t foldr replace []? Yes, yes it could. In
foldr op acc as, that acc ultimately replaces the [] in as. Well then,
let’s put this to use in concat. All we need to do is make sure the
second argument to concat becomes that acc.
concat :: [a] -> [a] -> [a]
concat = \as bs -> foldr _ bs as

And what about that placeholder _ we left? Well, if you recall, we


also said that, intuitively, the op in foldr op acc as replaced every
occurrence of (:) in as. But in our case, the uses of (:) in as are just
fine, so we don’t really need to change them. Let’s keep them where
they are by replacing them with themselves.

concat :: [a] -> [a] -> [a]


concat = \as bs -> foldr (:) bs as

That’s it. That’s concat. Try it. Use equational reasoning to prove
the concatenation of any list you want. Actually, it’s quite
interesting to see what happens when either as or bs are the empty
list [], so maybe let’s do that exercise here. Let’s see it for bs first.
That is, let’s use equational reasoning to see how concat as []
reduces.

concat as []
== foldr (:) [] as
== as

Wait, what? Well, yes, we said many times before that foldr (:) []
was the same as id for lists, so here we are essentially asking for the
identity of as, which is indeed as. And what about making [] our as
instead?
concat [] bs
== foldr (:) bs []
== bs

We didn’t say it explicitly before, but it turns out that \bs → foldr
(:) bs [] is also an identity function for lists. Think about it, foldr
op acc [] has no more elements to process, so it simply returns acc,
the result accumulated so far, unmodified. So if we make bs our acc,
concat [] bs will effectively return that same bs given as input. In
other words, the following is true.

xs == foldr (:) [] xs == foldr (:) xs []

So there we have concat, which can also be written in a more


interesting manner using flip and a point-free style.

concat :: [a] -> [a] -> [a]


concat = flip (foldr (:))

Quite a surprise, isn’t it?


82. Discovery
Almost every time we encounter something that behaves as an
identity in the wild, chances are we are facing something
interesting. And concat is no exception. So let’s see what we have.

First, we know that concat [] xs and concat xs [] are the same as xs.

Second, we know, or at least we expect, that if we concatenate two


lists [1, 2] and [3, 4] into [1, 2, 3, 4], and then we further
concatenate that result with [5, 6], we should end up with [1, 2,
3, 4, 5, 6].

concat (concat [1, 2] [3, 4]) [5, 6]


== [1, 2, 3, 4, 5, 6]

But perhaps more importantly, we could also arrive to that same


result by concatenating [1, 2] with the result of concatenating [3,
4] and [5, 6].

concat [1, 2] (concat [3, 4] [5, 6])


== [1, 2, 3, 4, 5, 6]

Generalizing this a bit, we can say for any three lists a, b and c, this is
true:

concat (concat a b) c == concat a (concat b c)

There is a name for this, and we know it. Perhaps it would be a bit
easier to see if concat, rather than being a function expected to be
used in prefix manner, was an operator intended for infix usage
such as + or *. Let’s have that infix operator, let it be ++. That is, two
plus symbols.

(a ++ b) ++ c == a ++ (b ++ c)

That’s right. concat, which from now on we will call ++, is an


associative operator just like + and *. But not only that. Just like
addition by 0 behaved as an identity function, and how
multiplication by 1 did the same, here, concatenation with the
empty list [] behaves as the identity function too. In other words,
the empty list [] is the unit, the identity element, for list
concatenation.

a ++ [] == a

And whether we concatenate the empty list on the right or on the


left doesn’t matter. The result is the same.

[] ++ a == a

List concatenation, in other words, just like the addition of


numbers or their multiplication, all paired with their respective
identity elements, seems to be a monoid.
83. Monoid
Intuitively, a monoid is a way of combining two values of a same
type, where one of those values could behave as an identity, into a
third value of that same type. For example, we combine 2 and 3 by
multiplying them into 6, or we combine [1, 2] and [] by
concatenating them into [1, 2].

That is, a monoid is two things: A value and a function. Or is it


three things? A type x, a value of that type x, and a function of type
x → x → x. Or perhaps four things? A type x, a value of that type x,
and function of type x → x → x, let’s call it f, where f a (f b c) and
f (f a b) c are equal. That is, f is an associative function.

Actually, it’s five things. It’s a type x, an associative function of type


x → x → x, let’s call it f and a value of that type x, let’s call it unit,
that behaves as the identity element for that function f, meaning
that f unit a, f a unit and a are all equal. Yes, five is good for now.
A type, a value, a function and two laws. One requiring that the
function be associative, and the other one saying that our chosen
value must behave as an identity element for that function.

We can’t do much about those laws beside promising we won’t


violate them. So we stand up, look out the window, and as we
marvel at the achievements of nature and mankind, as the thought
of a loved one warms our heart, we thereby swear to the skies that
our monoids will always be true, and that the burden of proving
this will be ours. We can, however, do something about that value
and that function. We know it’s important to keep them separate,
but it’s also important that they always be close enough. Otherwise,
if one’s gone, we’d have a monoid no more. We need to pair them
somehow.
84. Design
We know how to pair things. For example, without much ado, we
can use Haskell’s weird (tuple, syntax) to pair an associative
function with its identity element.

addition :: (Natural -> Natural -> Natural, Natural)


addition = ((+), 0)

Here we are saying that addition will be the earthly representation


of our monoid. It’s a pair, a tuple, made out of an associative
function (+) and its identity element 0. But there’s something else
here, too. We grown-ups probably miss it because we are too easily
blinded by what we want to see. But if we take a step back to
contemplate the landscape, our inner child will notice that the most
prominent figure here, actually, is the Natural type. We see it in the
type of the identity element 0, and we see it all over the type of (+)
too. In fact, maybe we see it too much, and this should be a sign
that things could be better. For comparison, let’s see how the
definition of the list concatenation monoid would look like.

concatenation :: ∀ a. ([a] -> [a] -> [a], [a])


concatenation = ((++), [])

Superficially, things might look a bit messier, but essentially, all the
type of concatenation is saying is that the contents of the list we
want to concatenate are irrelevant. Our a, universally quantified,
could be blackholes or rainbows. It wouldn’t matter, for we’d be
able to concatenate them nonetheless.

In concatenation we have the surprise [a] all over the place, and in
addition we have the same Natural everywhere too. Both monoids
work just fine, but repeating the same thing over and over again is
tiresome. Let’s avoid this by using a custom product type, rather
than Haskell’s tuples.

data Monoid x = Monoid x (x -> x -> x)

Let’s see Monoid in action. It will help us appreciate its merits.

addition :: Monoid Natural


addition = Monoid 0 (+)

multiplication :: Monoid Natural


multiplication = Monoid 1 (*)

concatenation :: ∀ a. Monoid [a]


concatenation = Monoid [] (++)

It looks neat. Rather than repeating our chosen type every time, we
just repeat it once inside the definition of the Monoid datatype,
where we have a value constructor also called Monoid with two fields
in it: One with a value of the mystery type x mentioned as the type-
parameter of the Monoid type-constructor, and another one with a
function making reference to that same x.

Moreover, whereas before we talked of how tuples containing


things of a particular type and satisfying some laws could be seen as
monoids, here we actually have a thing called “monoid”. This is an
improvement in the human communication front, for it’s now
easier to talk about these things out loud. But more importantly, it
is a triumph on the type-checking front, seeing how the type-
checker will tell us that “a Monoid Natural was expected, not a
String”, or something along those lines, if we ever make a mistake
worthy of that message. Interesting things deserve a name.

Alright, we have Monoid. What can we do with it? Well, for example,
we said that while foldl and foldr don’t really need a monoid to
work, we can most certainly fold a list according to a monoid’s
intention if we have one. Let’s try and wrap foldr, say, so that it
takes a Monoid x rather than separately taking an initial accumulator
and an accumulating function.

foldrMonoid :: Monoid x -> [x] -> x


foldrMonoid = \(Monoid unit f) -> foldr f unit

Quite an impovement, I’d say. We are partially applying foldr to


the function and unit of our monoid so that all that’s left to
provide is the list to fold. Of course, foldrMonoid is less polymorphic
than foldr, where the output type of the fold was not necessarily
the same as that of the elements in the list, but that’s an expected
consequence of the type of our monoid function being x → x → x
rather than x → y → y, say. In exchange for this sacrifice, we are
lowering the number of values the caller of foldrMonoid needs to
juggle at the same time, as well as the cognitive effort it takes to
understand the type and behaviour of this function. So much so,
actually, that talking about foldr vs foldl is not necessary anymore.
Why? Well, because monoids are associative, meaning that,
semantically at least, it doesn’t mather whether we start
accumulating from the left or from the right. The result will be the
same anyway. In Haskell we call this function mconcat, an excellent
name that doesn’t make sense yet.

mconcat :: Monoid x -> [x] -> x


In practice, mconcat is often implemented with foldr because of its
support for infinite lists, but that’s unrelated to what we are
discussing, so just pretend you didn’t read this.

With mconcat in place, we can redefine our sum and product from
before in a semantically more agreeable way.

sum :: [Natural] -> Natural


sum = mconcat multiplication

product :: [Natural] -> Natural


product = mconcat addition

Wait, what? There’s something very wrong here.


85. Vocabulary
There’s nothing wrong with our Monoid datatype. Yet, here we are,
complaining that our product adds and our sum multiplies. What
happened? They shared their types, that’s what happenend. Just
like how when doing arithmethic we can mistake 2 with 4, seeing
how they are both values of type Natural, we can mistake
multiplication with addition just as well, for they also share a same
Monoid Natural type.

While in theory sufficient, and quite frankly rather beautiful, our


approach didn’t leverage the types as much as it could have and has
thus become a weapon. Or, well, something that compiles yet does
the unexpected. How can we fix this? How can prevent
multiplying sums and additive products from existing at all?

It’s the type-checker who decides what compiles and what doesn’t,
so all we need to do is speak its language, types, and ask for it.
Luckily for us, we have a good starting point. Our monoids always
refer to some type in them. Both addition and multiplication talk
about Natural, say, and concatenation talks about [a]. But therein
lies our problem.

It is true that Natural numbers can be added, yes, and it’s also true
that they can be multiplied. All that is true. But we can enrich these
numbers a bit, with their intentions, and let the type-checker worry
about any misplaced expectations.

data Sum = Sum Natural

This new datatype, Sum, is simply a wrapper around the Natural


type. When we construct a value of type Sum using the Sum value-
constructor, as in Sum 3, all we are doing is earmarking that Natural
number 3 for a particular purpose. Its type is not just Natural
anymore, so a function expecting a Natural number as input will
reject it. Imagine we had a function called double that multiplied
numbers by two.

double :: Natural -> Natural


double = \x -> x * 2

Applying double to the Natural number 3, as in double 3, would


type-check just fine and eventually result in 6. But an application of
double to Sum 3, as in double (Sum 3), will be rejected by the type-
checker because it was a value of type Natural, not of type Sum, what
was expected. We humans know that there is a Natural number
hidden inside this value of type Sum, but the compiler doesn’t. Or
rather, it does, but it refuses to just ignore its belonging to a
different species. Ultimately, all computers ever see are numbers.
Sum 3? 432. Summer? 22. "telescope"? 324893. double? 47328902. But
for all humane intents and purposes, these numbers on their own
are just nonsense. We have types because they convey different
ideas that we don’t want to get mixed up. For us, the Sum type
conveys the idea that the Natural number is expected to be added
through the addition monoid.

Sum is new vocabulary that both we and the type-checker


understand. The only thing that’s interesting about Sum, from the
point of view of the type-checker, is that its name, its identity if you
will, is different from that of every other one that came before. This
makes Sum unique, which makes it impossible to mistake a value of
type Sum for a value of any other type. But the interpretation of Sum
as a value to be combined through the addition monoid, on the
other hand, is a choice we made at the level of expressions, and as
such, the type-checker will forever remain unaware of it. The way
we give meaning to Sum is by implementing functions that make use
of it in the way we expect them to. So let’s give it meaning by re-
implement addition in a way that takes Sum into account.

addition :: Monoid Sum


addition =
Monoid (Sum 0) (\(Sum a) (Sum b) -> Sum (a + b))

We said Sum is essentially a wrapper around a Natural number. So


here we are wrapping the Natural number 0 to be the identity
element of this monoid, and in our associative function, before and
after actually adding our numbers, we are unwrapping and re-
wrapping these Sums. Let’s see this in detail.

As we know, the type of addition, Monoid Sum, mandates that the


type of its identity element be Sum, and that the type of its
associative function be Sum → Sum → Sum. Creating a value of type Sum
out of a Natural number is quite straightforward, all we need to do
is apply the value-constructor Sum to the Natural number. And
similarly, extracting the Natural number from inside the Sum
expression is quite simple. All we have to do is pattern-match on Sum
n to obtain that n. Actually, we can define a function that does this
for us.

unSum :: Sum -> Natural


unSum = \(Sum n) -> n

It’s interesting to notice that composing Sum and unSum results in an


identity function for values of type type Sum.
compose Sum unSum :: Sum -> Sum

We can prove this is true by using equational reasoning. Actually,


let’s do it. It should be quick. Let’s prove that compose Sum unSum
(Sum n) equals Sum n.

compose Sum unSum (Sum n)


-- First we reduce `compose`.
== Sum (unSum (Sum n))
-- Then we inline `unSum`.
== Sum ((\(Sum n) -> n) (Sum n))
-- Finally we beta-reduce.
== Sum n

And vice-versa, compose unSum Sum functions as an identity function


for values of type Natural. You can do the equational reasoning to
prove this yourself.

It’s customary to call functions such as unSum, intended to just


remove a wrapper like the one we named Sum, “unSomething”.
Names matter to us humans, and talking about “wrapping” and
“unwrapping” things simplifies communication.

And, by the way, we just accidentally proved that Sum and Natural
are isomorphic. Using Sum and unSum we can convert between them
without any loss of information. Isn’t that nice? Not all accidents
are bad.

Anyway, back to our addition monoid. As we know, in our Monoid,


we are receiving values of type Sum wherever Sum appears as an
argument in negative position, and we are responsible for producing
values of type Sum everywhere Sum appears in a positive position.
data Monoid x = Monoid x (x -> x -> x)
+ +++++++++++++
+ - - +

In other words, we apply the Sum constructor wherever x, which in


our case is Sum, appears in positive position. And we pattern-match
on Sum n everywhere the x appears in negative position, in order to
extract the Natural numbers inside these Sums and add them together
before re-wrapping them in yet another Sum.

addition :: Monoid Sum


addition =
Monoid (Sum 0) (\(Sum a) (Sum b) -> Sum (a + b))

Of course, rather than pattern-mathing on the Sum constructor, we


could have used unSum instead.

addition :: Monoid Sum


addition =
Monoid (Sum 0) (\a b -> Sum (unSum a + unSum b))

Here, a and b are of type Sum rather than Natural, but the whole
thing means the same anyway, so it doesn’t really matter which
version we choose.

Alright, we have redefined addition to work exclusively with Sums.


Now let’s have sum, the function supposed to add togther all the
Natural numbers on a list, use it.

sum :: [Natural] -> Natural


sum = mconcat addition
Boom! If we try this, type-checking fails with an error saying
something about a value of type [Sum] being expected where a value
of type [Natural] was given. So not only does the wrong sum fail to
compile, the one that multiplied numbers rather than adding them,
but also the right one fails, the one which actually adds numbers.
But while at first we might find this depressing, a failure, what’s
really happening is that we have been successful, yes we have.
86. Concerns
In Sum we created new vocabulary that the type-checker could
understand. Vocabulary that we could use to talk to the compiler
and say “listen, my friend, this is the only type of numbers we’ll
ever deal with”. However, to make effective use of this new
vocabulary for our monoidal needs, we had to change our addition
monoid so that it worked with numeric values wrapped in Sum,
rather than with plain old Naturals. Now, we need to do something
similar in sum.

In sum we are blindly using mconcat, whose type is Monoid x → [x] →


x, and therein lies the problem. What is happening is that when we
apply mconcat to addition, of type Monoid Sum, the mystery x in our
type becomes Sum everywhere else. In other words, addition is
forcing every value that interacts with it to have the type Sum. That’s
great, that’s what we wanted, isn’t it? This should be the type of
sum, according to mconcat.

sum :: [Sum] -> Sum

This works just fine. However, we’ve trespassed. We’ve crossed a


forbidden boundary, and we shouldn’t have. The users of sum, those
who just need to add numbers together, shouldn’t have to concern
themselves with things such as Sum and monoids. Sure, internally,
we are using this marvelous and unique vocabulary to implement
sum, but we could as well have continued to use foldr (+) 0 as
before, and from the point of view of the users of sum it would have
been equally fine. They don’t care about how sum is made, all they
care about is what sum accomplishes in the end.

This is the essence of functional programming. Our programs are


essentially functions made out of functions. But at every step of the
way, these functions have different and reasonable concerns. Just
like how when running we don’t need to think about our muscles
contracting, about the impulses in our nerves, or about cells
suddenly requiring more oxygen, functional programming is about
worrying about the right thing at the right time. Never less, never
more. In this new sum, we have our runner worrying about cells.
That’s not good.

We need to change sum so that rather than having the type [Sum] →
Sum, it can keep its previous type [Natural] → Natural. That is, we
need to modify the types of both the input and the output of sum.
Alright, that’s not a problem, we know how to do it.

dimap :: Profunctor p
=> (a -> c) -> (b -> d) -> p c b -> p a d

Remember Profunctors? Those were lovely. More specifically,


specializing the type of dimap for our needs, we get something like
this:

dimap :: ([Natural] -> [Sum])


-> (Sum -> Natural)
-> ([Sum] -> Sum)
-> ([Natural] -> Natural)

Don’t let the rather big type scare you, what’s happening is really
easy. Let’s start from the very end. This use of dimap returns a value
of type [Natural] → Natural, which is exactly the type we want sum to
have. Great. Then, we have an argument of type [Sum] → Sum, which
is exactly the type that mconcat addition has. Excellent. Let’s start
writing this down.
sum :: [Natural] -> Natural
sum = dimap _ _ (mconcat addition)

All we need now is a function of type [Natural] → [Sum] to take the


place of that first placeholder _, and another one of type Sum →
Natural to replace the second placeholder _.

We will use unSum as our value of type Sum → Natural. There’s not
much to say about it beyond what we have already said. unSum is
here and it has the right type, so let’s just use it.

sum :: [Natural] -> Natural


sum = dimap _ unSum (mconcat addition)

What about the other placeholder? The function that takes its place
is expected to convert every element in a list of Naturals into a value
of type Sum. We know how to convert one Natural into a Sum by
simply applying the Sum value-constructor, alright, but an entire list
of them? Crazy stuff.

Just kidding. Remember lists are a Functor too, meaning we can use
fmap, of type (a → b) → ([a] → [b]), to lift the Sum value-constructor
of type Natural → Sum into a function of type [Natural] → [Sum],
which is exactly what we need.

sum :: [Natural] -> Natural


sum = dimap (fmap Sum) unSum (mconcat addition)

Beautiful. Now sum has exactly the same type as before, but
internally it relies on Sum and the addition monoid. Of course, we
could have written this in a different way, but any difference would
be just superficial. The fundamental issue of converting between
Sum and Natural back and forth will always be present.

sum :: [Natural] -> Natural


sum = \xs -> unSum (mconcat addition (fmap Sum xs))

The experienced programmer might point out, concerned, that we


are wasting computing power converting Naturals into Sums and
back just to accommodate this, and in theory this is true. In
practice, however, not only is Haskell beautiful, but also, as of the
beginning of the 21st century, its compiler GHC is rather excellent
as well. And among other things it can realize that Sum and Natural,
despite their different types, are essentially the same. Knowing this,
Sum will continue to exist at the type level, but it’s existence as a term
will have no cost whatsoever. Sometimes the compiler needs a
couple of hints here and there to achieve this, but ultimately, it will
happen. So experienced programmer, don’t worry too much about
this.

Could we accidentally mix addition and a multiplication monoid of


type, say, Monoid Product, where Product is to multiplication what Sum
is to addition?

data Product = Product Natural

multiplication :: Monoid Product


multiplication =
Monoid (Product 1)
(\(Product a) (Product b) -> Product (a * b))

Yes, of course we could mix them up, but since we are not dealing
directly with Naturals anymore, making that mistake would involve
three accidents, rather than one, for we’d also need to mistake fmap
Sum for fmap Product and unSum for unProduct. Chances are minimal.

Alright, we’ve accomplished something nice. In summary, we


created these wrappers Sum and Product so that addition and
multiplication, our monoids, couldn’t be mistaken for each other.
Of course we could get the implementation of addition or
multiplication themselves wrong, if we mistake 0 for 5, say. But,
quite frankly, that could be described as lack of responsibility.
Ultimately, addition and multiplication are our sources of truth, the
monoids themselves, so we need to make sure they do what we
want. The computer can go quite far, but at some point we need to
say “computer, this is what we want”. And this is fine, because we
are the programmers, we decide what ultimately happens. In our
case, the definition of our monoid is the only place where we ever
need to pay attention. Just one place, everything else builds on top
of that. mconcat has been the only use case for our monoids so far,
sure, but this was just an example: Monoids are everywhere, and in
reality we use them all the time in a myriad different ways beyond
mconcat. So yes, it is scary, but it is also quite beautiful. And don’t
worry, we have very boring tools that can help us get this right too,
we’ll see them later on. To sum up, we will always need to tell the
computer what to do at least once, somewhere, for we are the
programmers and not them.

Anyway, beyond the addition monoid, say, we don’t have really


another use for our Sum type. That is, we expect that there will be
just one way to interpret Sum as a monoid, and never more. Actually,
if we could somehow prevent a different monoidal interpretation
for Sum, that would be even better. Can we do that? Can we have
the Sum type itself, rather than addition, determine its behavior as a
monoid?
87. Comfort
There’s nothing wrong with our Monoid datatype. But there wasn’t
anything wrong with our representation of a monoid as a tuple
either, and yet we somehow improved it. So let’s improve this too.
In Haskell, Monoid is not a datatype but a typeclass, just like Functor
and friends.

class Monoid x where


mempty :: x
mappend :: x -> x -> x

How is this better? Let’s see. First, and unrelated, notice that this
typeclass is the first one we see having more than one method. This
is fine. Just like product types can have many fields, typeclasses can
have many methods too. Here, the Monoid typeclass has two
methods named mempty and mappend. And if we compare this
typeclass with the Monoid datatype we defined before, we’ll see the
resemblance is remarkable.

data Monoid x = Monoid x (x -> x -> x)

It seems that mempty is the name this typeclass is giving to the


identity element of our monoid, and that mappend is the name it
gives to the monoid’s associative function. And, since there’s
nothing more to see, this must be all there is to the Monoid typeclass.
So without further ado, let’s dive in. Let’s make Sum be our x and
implement an instance for this typeclass.
instance Monoid Sum where
mempty = Sum 0
mappend = \(Sum a) (Sum b) -> Sum (a + b)

It’s not what we have gained from this instance what matters, but
what we’ve lost. Which, actually, is also what we gained, so I guess
it’s both. Anyway, addition, the previous definition of our monoid,
is gone. Poof. We don’t need it anymore because its code lives in
the Monoid instance for Sum now. And this is perfect, because while
previously we intended the Sum type to determine the meaning of
our monoid, in reality it was addition, who happened to mention
Sum, who did. But now Sum must decide who it wants to be, for there
can only be one instance of the Monoid typeclass for Sum, and
whatever that one instance decides, will be the monoidal behavior
of Sum. It will be the truth.

So let’s profit from this. Let’s see, for example, how the sum
function, the one that adds Natural numbers, would be
implemented using this function.

sum :: [Natural] -> Natural


sum = dimap (fmap Sum) unSum mconcat

The only thing that changed here, compared to our last definition
of sum, is that we are not applying mconcat to addition anymore. So
how does mconcat know that it needs to add the elements in our list?
The answer is in mconcat itself.

mconcat :: Monoid x => [x] -> x


mconcat = foldr mappend mempty
What moncat is saying is that given a list of elements of type x for
which there exists a Monoid instance, such as our Sum, it will fold that
list using mappend as the accumulating function and mempty as the
accumulator. In other words, the value of type Monoid x we were
explicitly passing around before, is now implicit. And all we need to
do for this to work, essentially, is pick the right x. And how does sum
pick this x? Both its use of the Sum value-constructor and the unSum
function force the Sum type to be this x. Anything else would fail to
type-check.

So there we have it. A typeclass approach that requires us to have


one type per monoid, making the type itself, rather than some wild
expression, the source of truth. And moreover, it makes for a more
comfortable experience, considering how we don’t explicitly have
to mention said gone monoid expression in our code anymore. For
completeness, here’s the code defining the rest of our monoids so
far:

instance Monoid Product where


mempty = Product 1
mappend = \(Product a) (Product b) -> Product (a * b)

instance Monoid [a] where


mempty = []
mappend = (++)

And something else. Considering how monoids have laws, and how
we appreciate seeing laws in typeclasses so that we know all their
instances behave as expected, the Monoid typeclass in Haskell is
accompanied by some comments requiring compliance with two
laws. First, an identity law, whereby mempty is required to behave as
an identity element:
mappend mempty x == x == mappend x mempty

And then an associativity law, in which mappend is required to be


and associative function:

mappend a (mappend b c) == mappend (mappend a b) c

That’s all there is to Monoid in Haskell. For now, anyway. Of course


there is more.
88. maybe
Generally speaking, to fold is to iteratively convert the constituent
parts of a whole into a new whole, which could be something else
entirely, by means of some higher-order function. Kind of. For
example, we iteratively convert all the applications of (:) and [] in a
list by replacing them with values or function applications. But this
idea of taking a whole and converting it to something else part by
part, in principle, sounds useful beyond lists.

data Maybe a = Nothing | Just a

Let’s see if we can come up with a function that folds a value of


type Maybe a somehow. We’ll call it foldMaybe. Now, we know
nothing about this function except that it can be used to construct
anything out of the constituent parts of a Maybe a. So for now, let’s
just say the output of this function will be some unknown,
universally quantified type z.

foldMaybe :: ∀ z. … -> z

Then, we need to deal with these “constituent parts” somehow,


whatever they might be. But we don’t like being told what to do, so
let’s try to discover this on our own. Let’s just deal with “the
whole”, with the entire Maybe a, at once.

foldMaybe :: ∀ a z. Maybe a -> z


foldMaybe = \ya ->
case ya of
Nothing -> ‽
Just a -> ‽
We were reckless, we are stuck. foldMaybe can’t construct values of
some unknown type z out of thin air. This is a situation similar to
the one we faced before when we dealt with undefined, also known
as bottom. Yes, we are stuck here ‽. Let’s remind ourselves how foldr
dealt with this, maybe we can find some inspiration there.

foldr :: ∀ a z. (a -> z -> z) -> z -> [a] -> z

We had different perspectives for understanding the behavior of


foldr, but the one that will help is now is the that saw foldr op acc
as essentially replacing the empty list constructor [] with acc, and
every use of “cons” (:) with an application of that op. In other
words, acc of type z is what we use whenever the list is empty, and
this op that somehow returns a z is what we use when we encounter
an element of type a in our list. And, if we consider that a value of
type Maybe a is essentially a one-element list, we can start copying
some of this ideas.

First, we’ll make sure foldMaybe is given a z that it can use whenever
it encounters the Nothing constructor, analogous to the empty list
constructor [].

foldMaybe :: ∀ a z. z -> Maybe a -> z


foldMaybe = \z ya ->
case ya of
Nothing -> z
Just a -> ‽

Then, we need something to deal with the “non-empty list” case.


That is, with the Just constructor. In the case of foldr, this is a
function of type a → z → z where the input of type a is the a in a :
rest, and the input value of type z is the result of recursively folding
the rest of the list. This makes sense for lists because they are a
recursive datatype, but Maybes are not, so perhaps we should just
drop that input z altogether, and instead have a function a → z that
will convert the a inside a Just constructor when it sees one. Let’s
try that.

foldMaybe :: ∀ a z. (a -> z) -> z -> Maybe a -> z


foldMaybe = \f z ya ->
case ya of
Nothing -> z
Just a -> f a

Yes, that’s it. This is foldMaybe. Let’s put it next to foldr so that we
can compare their types.

foldMaybe :: (a -> z) -> z -> Maybe a -> z


foldr :: (a -> z -> z) -> z -> [a] -> z

The resemblance is quite apparent. Now, in Haskell, this function


is not called foldMaybe. A bit confusingly, its name is maybe, all in
lowercase, and the order of its input parameters also changes. But
leaving aside those superficial matters, it is essentially the same
thing.

maybe :: z -> (a -> z) -> Maybe a -> z

But why would we want to fold a Maybe, anyway? Couldn’t we just


perform a case analysis on the Maybe a value, pattern-match on the
different constructors, and manually deal with them as we’ve doing
so far? Well, yes, of course we could, but this is functional
programming, so we appreciate having that same behavior
packaged in a function that we can readily apply and compose time
and time again. We will use maybe shortly.
89. either
Can we fold an Either a b too? Of course we can. Actually, why
don’t you go ahead and implement this yourself?

either :: (a -> z) -> (b -> z) -> Either a b -> z

Generally speaking, the term “fold” is closely related to list-like


things that have some kind of recursive structure, so saying that
maybe and either are “folds” is perhaps not entirely accurate. Later
on we’ll see how these things can be generalized, but for now,
“fold” is alright.

Anyway, luckily for you, the type of lowercase either fully


determines its implementation. Unfortunately, this wasn’t the case
neither for foldr, foldl nor maybe. For example, we could have
implemented maybe as follows, it would have compiled, but it
wouldn’t have done quite what was expected of it.

maybe :: z -> (a -> z) -> Maybe a -> z


maybe = \z f ya ->
case ya of
Nothing -> z
Just a -> z

That is, it wouldn’t have used f at all. And how do we know what’s
expected of a well behaved maybe? Well, we don’t. It really is up to
the designer of this function to come up with a description for it
and make sure its implementation matches that description.
However, our fluffy intuition for what a “fold” is should suggest
some sensible ideas. We could say, for example, that the following
equality is expected to be true:
y == maybe Nothing Just y

In other words, maybe Nothing Just is an identity function for values


of type Maybe a, for all a. And when we consider this equality
together with the parametric polymorphism of maybe, which says
that it must return a z which can only be constructed by using one
of the first two inputs to maybe, ruling out \_ _ y → y as the
implementation of this identity function, we are safe.

So go ahead, implement either, and think about what makes it


different from maybe in this regard.
90. Bool
Another type we’ll frequently encounter is Bool, which stands for
boolean, and represents the idea of truth in logic. We use values of
type Bool to denote whether something is either true or false. Either?
Or? That sounds like a sum type, a coproduct.

data Bool = True | False

Indeed. In logic, things are either true or false, and Bool correctly
represents that. For example, we could use a boolean as the answer
to “is this list empty?”.

isEmpty :: [a] -> Bool


isEmpty = \xs ->
case xs of
[] -> True
_ -> False

isEmpty returns True when the given list is [], and False whenever it’s
not. Remember, that wildcard _ will successfully pattern-match
against anything that has not successfully pattern-matched before.

There’s not much more to say about Bool itself. It’s just a rather
boring datatype with two possible values.

Can we fold a Bool? Yes, of course we can. Remember, when we


fold, we are trying to obtain a value of some type z by addressing
each of the constituent parts of our datatype separately. In our case,
those parts are True and False. So let’s introduce a function called
bool to do just that.
bool :: z -> z -> Bool -> z

We expect bool to replace True with one of the z inputs, and False
with the other one. Which one, though? Which of the following
implementations of bool is the correct one? And to make it a bit
more interesting, let’s say that if we pick the wrong one, we die.

\x y b -> case b of { True -> x; False -> y }

\x y b -> case b of { True -> y; False -> x }

This is one unfair game. It’s should be easy to understand what’s


happening if we compare the types of bool, maybe and either.

either :: (a -> z) -> (b -> z) -> Either a b -> z


maybe :: z -> (b -> z) -> Maybe b -> z
bool :: z -> z -> Bool -> z

Each of Either, Maybe and Bool have two constructors, and


conceptually, they only differ from each other in their payloads.
Either, for example, has payloads in both of its contructors. And
this, combined with the parametric polymorphism in either
mandating that a z be returned somehow, forces either to use a → z
when it encounters a Left constructor, and b → z otherwise. either
is beautiful.
either :: (a -> z) -> (b -> z) -> Either a b -> z
either = \f g e ->
case e of
Left a -> f a
Right b -> g b

Similarly, maybe is still forced to use that standalone z when it


encounters a Nothing constructor, for it has no b to which to apply b
→ z. But on the other hand, when it encounters a Just constructor
with a b in it, it can choose to apply b → z or just return that
standalone z, ignoring b altogether. And choice, in computers,
sometimes means catastrophe. We are forced to clarify what
happens in that case as part of our documentation. With bool
things are even worse, because we have two standalone zs to pick
from, and neither True nor False have payloads that could help us
decide which one to use. We are at a loss, and must instead rely on
documentation to speak the truth. One truth, its truth, which
states that bool will return the first z when the given Bool is False,
and the second z otherwise.

x == bool False True x

Thus spoke identity, with a very weak voice. This time, nothing
mandated this choice.

Anyway, booleans are not immediately interesting. What’s


interesting is what we can do when we have many of them, how we
can combine them.
91. Conjunction
In logic, conjunction is the operation through which two boolean
values become one by agreeing on the truth of something. That is,
the conjunction of two boolean values a and b is itself true, if both a
and b are themselves true. Otherwise, it’s false. In programming, we
usually call this operation “and”.

and :: Bool -> Bool -> Bool


and = \a b ->
case a of
False ->
case b of
False -> False
True -> False
True ->
case b of
False -> False
True -> True

That’s ugly. It gets the job done, sure, it only returns True if both a
and b are True, but it is nonetheless ugly. Let’s try to clean this up.
First, let’s realize that as soon as we discover that a is False, we can
just return False without having to look at b.
and :: Bool -> Bool -> Bool
and = \a b ->
case a of
False -> False
True ->
case b of
False -> False
True -> True

Second, notice how our analysis of b is saying that if b is False, then


we return False, and if it is True, we return True. That is, we are
saying that whenever a is True, we will return a new Bool with the
same value as b. Well, in that case, we might as well return b itself.

and :: Bool -> Bool -> Bool


and = \a b ->
case a of
False -> False
True -> b

Great, that’s looking better. But could we use our bool fold instead?
Sure, why not.

and :: Bool -> Bool -> Bool


and = \a b -> bool False b a

This is much nicer. If a is False we return False, otherwise we return


b. But, actually, there is more. It turns out that the conjunction of
two booleans, and, is a commutative operation, meaning that saying
and a b or and b a leads to exactly the same result, which implies
that in theory we are allowed to move around our as and bs to
accommodate our needs.

and :: Bool -> Bool -> Bool


and = \a b -> bool False a b

What needs? The need to realize that in \a b → bool False a b we


are facing an eta-expanded form of \a → bool False a, which in turn
is an eta-expanded form of bool False. So what about eta-
converting all of this, and leaving bool partially applied instead?

and :: Bool -> Bool -> Bool


and = bool False

Ah, functional programming. Nice. And look, all of these equalities


hold.

and True True == True


and True False == False
and False True == False
and False False == False

This is true, and in general this is right. But in Haskell, this is wrong
too.
92. Laziness
Contrary to almost every programming language out there, Haskell
is a lazy one. And contrary to civil prejudice and family values,
being lazy is often quite good.

A language being lazy, or more precisely the evaluation strategy of


the language being lazy, means that an expression will only be
evaluated when truly necessary, and never before. This is clever.
Let’s see how.

We are in our kitchen and we decide to cook something new.


However, in order to cook this, we’ll need some utensils and
ingredients. We can’t afford buying new utensils today, though, so
we’ll only start cooking if the utensils we already have are sufficient.
Moreover, we remember that our pantry is almost empty, which
means that we’ll also need to go to the market to buy the
ingredients that we need, and only if we can find them all we’ll be
able to start cooking. So, we have two questions: Whether we have
utensils, and whether we have the ingredients that we need. Only if
we have all of this can we cook. In other words, our ability to cook
depends on the conjunction of our having utensils and ingredients.

Being as lazy as we are, we take one thing at a time. We start by


looking for our utensils because we dread going to the market, so if
at all possible, we would like to avoid it. The kitchen is right here,
so we look around and check whether we have everything we need,
and eventually store in a value named we_have_utensils of type Bool
our judgement about this fact. This is how we would proceed in
real life, being the lazy cooks we are. If it is True that
we_have_utensils, then we go to the market to find out whether
we_have_ingredients or not. But if it is False that we
we_have_utensils, then we can avoid that trip to the market
altogether, for whether we_have_ingredients or not, we still won’t be
able to cook without utensils.

Haskell is lazy like that. When we ask for the conjunction of two
Bool values, when we say and a b, we are asking for them to be
considered and eventually conjoined in that order: First a, then b.
That is, when we ask for the logical conjunction of we_have_utensils
and we_have_ingredients, we want Haskell to avoid us that trip to
the market if possible by first evaluating whether we_have_utensils,
and only if this is True, force a trip to see whether
we_have_ingredients or not. However, when we implemented and as
bool False, we broke this.

we_can_cook :: Bool
we_can_cook = and we_have_utensils we_have_ingredients

Let’s use equational reasoning to see how the evaluation of this


application of and proceeds.

we_can_cook
== and we_have_utensils we_have_ingredients
== bool False we_have_utensils we_have_ingredients
== case we_have_ingredients of
False -> False
True -> we_have_utensils

In other words, our implementation of and as bool False is


scrutinizing we_have_ingredients first, before considering whether
we_have_utensils at all. This is exactly the opposite of what we
wanted. This is wrong. So yes, while on paper it is true that the
logical conjunction of two boolean values is commutative, meaning
that and a b and and b a shall result in exactly the same value, this
model doesn’t take into account the cost of obtaining the truths to
conjoin. Mathematics is lucky like that, it needs not care about
labour.

So we just change the order of the arguments, right? That is, we say
and we_have_ingredients we_have_utensils rather than and
we_have_utensils we_have_ingredients. Yes, sure, that works.
However, booleans and this left-to-right way of dealing with them
lazily have become so ingrained in programming, that flipping the
order of these arguments in order to accommodate and encourage a
sociopath and might not be a sane long-term choice. Can we fix it?
Of course we can. All we have to do is go back to that time when
and was behaving perfectly fine, before we decided to play with
commutativity. We can accomplish this by reusing one of our
previous definitions, or by using flip to swap the order of the input
parameters in our current definition.

and :: Bool -> Bool -> Bool


and = flip (bool False)

I’ll leave it up to you to prove, using equational reasoning, that this


is indeed correct.
93. Thunk
So how do we reason about laziness? How do we tell people about
and's lazy behavior? How do encourage the conjoining of truths?
Can we do that at all? We can, yes we can. Laziness can be an
elusive concept, and it may take us a while to be able to
comfortably work with it. But as anything worth talking about, we
have precise vocabulary for it, so let’s talk.

First, that which among friends we call “laziness”, technically, is


called “call-by-need evaluation strategy”, a name that perfectly
suggests how need will trigger evaluation. But here we are among
friends, so let’s continue talking about how lazy things are instead.

Second, while we previously suggested that everything in Haskell


was an expression, and while that was “true”, in reality, almost
everything is actually a thunk. We juggle many truths here, and at
different times some are more useful than others. In part, this
abundance of truth is what makes programming and mathematics
so complex and eternally exasperating. The secret to happiness, or
at least to effectively functioning in this fractal truth landscape,
seems to be in acknowledging that occasionally we’ll have to
content ourselves with the truth that addresses our immediate
concerns, while remaining fully aware that we could be mistaken.
Our empire could collapse at any time. There will always be a latent
truth, a deeper one, comprehending more than what we’ve dared
care for so far, quite likely proving us wrong. The silver lining is
that we never stop learning: If we have more questions, we’ll also
have more answers. And then we’ll have even more questions, of
course, for that’s the price of knowledge. It’s humbling, it’s fun, it’s
necessary.
Thunk, a broken tense form of the English verb “to think”, made
noun by the grace of this language’s disregard for tradition, is the
name we give to expressions that haven’t been evaluated yet. In
Haskell, when we say id 3, for example, this doesn’t immediately
become 3. Likewise, and True False doesn’t immediately become
False. Instead, these expressions become a thunk, a commitment to
deliver a value of the expected type when requested and not before.

We want to defer computations for as long as possible, hoping,


ironically, that some of them never run at all. This drastically
changes the way we approach problems, the way we design
solutions, because rather than worrying that the computer might
be doing too much work, we can optimistically say things such as
and we_have_utensils we_have_ingredients and trust that and won’t
make us go to the market unless we really have to. Without laziness,
we just can’t be so optimistic. Thunks help us achieve this. But
moreover, as a separate virtue, if we actually need to evaluate a
thunk for a particular purpose, then the profits of this labour need
not end there. Once a thunk has been evaluated, once its ultimate
value has been computed, it will be made available for others to
exploit too without having to compute it all over again. Consider
and we_have_ingredients we_have_ingredients. Are we really
planning to go to the market twice? For what? To double check if
we have the ingredients we need? That would be a waste of time,
and Haskell, thunks, know that. What happens instead is that we go
to the market once, learn and commit to memory our
understanding about the availability of ingredients, and the next
time we are asked about it we just recall that answer, knowing that
we have already thought about it before. Thus the etymology of the
name.

We also implicitly suggested that Haskell’s and was somehow


special, different from and in other languages. And it’s true, it is
different, but not because it’s special, rather because it is not. Most
programming languages are strict, not lazy, meaning that when we
say f a b in them, all of a and b are fully evaluated before f is called.
There are no thunks nor any other means of automatically
deferring computations for us. But Haskell it’s not like that, in
Haskell f will be applied to its inputs a and b right away, even if a
and b haven’t been evaluated yet. If f ever needs to know more
about a or b, then their thunks will be automatically evaluated and
replaced with actual values. Generally speaking, it is not possible to
implement functions like and in other languages in such a
straightforward manner. However, logical conjunction is quite
prominent in programming, and almost every programming
language out there embraces the idea of market trip avoidance by
automatically deferring the computation of the second input
argument to and as an optimization, so as to prevent programs from
doing more work than necessary. But how do they deal with this, if
they are not lazy? Corruption, that’s how. Mostly, they give
booleans a special treatment. Whereas in Haskell Bool is a datatype
we can define, in most other languages booleans and functions on
them like and are baked into the language itself. In fact, being as
baked in as they are, and having semantics different to the rest of
the language, “functions” like and are rarely actual functions, they
are some kind of kludge instead. Not in Haskell, though. We have
kludges, sure, but not these.
94. Weak head
Let’s build a list. An infinitely long list where every element is 0.
Laziness makes this possible. Let’s see how.

zeros :: [Natural]
zeros = 0 : zeros

The first thing to keep in mind is that just like how defining
undefined, an expression that looped itself to oblivion, didn’t make
our programs crash, merely defining zeros doesn’t make our
program loop forever chasing its tail either. Essentially, zeros is a list
of type [Natural] obtained by applying (:) to the Natural number 0
and to a recursive use of the name zeros. The type-checker accepts
this because zeros has type [Natural], which is exactly what our use
of (:) expected. Let’s use equational reasoning to see how the 0s in
zeros come to be.

zeros
-- We inline the definition of 'zeros'
== 0 : zeros
-- And then we do the same again and again …
== 0 : (0 : zeros)
== 0 : (0 : (0 : zeros))
== 0 : (0 : (0 : (0 : zeros)))
== 0 : (0 : (0 : (0 : (0 : …))))

Now, if we wanted to apply sum to zeros, say, the computation


would never end. Our program would diverge. This should be easy
to see, considering how sum is trying to come up with a finite
number as the result of adding together the elements of a list that
happens to be infinitely long. A futile endeavour, we know, but sum
doesn’t. Unfortunately, sum zeros will type-check just fine. It’s only
when we attempt to compute sum zeros that our program goes into
an infinite loop, diverges, never halts, just like undefined never did.
This is yet another manifestation of the Halting Problem that
plagues general purpose programming languages. But of course,
divergence is not what we want infinite lists for. So let’s go deeper,
let’s try to understand the lazy nature of lists and see if we can
profit from it.

When we say zeros = 0 : zeros, we are creating a thunk. In fact, all


Haskell sees is something like this:

zeros :: [Natural]
zeros = <thunk>

Mind you, this is not proper Haskell. We are just using <thunk> to
pinpoint where Haskell sees a thunk.

To understand how this thunk becomes an actual value, we will


need to force its evaluation somehow and see what’s underneath.
Our most unkind sum does that, but it is also too eager to see
everything, too strict. We need a gentler function this time, one that
will kindly understand our list without taking a peek, like isEmpty.

isEmpty :: [x] -> Bool


isEmpty = \xs ->
case xs of
[] -> True
_ -> False

This function, isEmpty, doesn’t really care about the contents of our
list. All it wants to do is scrutinize the outermost constructor, the
one farthest from [], and check whether it is [] or something else.
Once we apply isEmpty to zeros, we get our False result as expected,
but something happens to zeros as well:

zeros :: [Natural]
zeros = <thunk> : <thunk>

Our zeros is not itself a thunk anymore. Rather, it is now known to


be an application of the (:) constructor to two other thunks. This
is not a fact hidden in the promise of a thunk anymore, this is
known. And it is important to realize that while this knowledge
doesn’t mention the 0 and zeros we originally gave as payloads to
(:), it is still enough knowledge for isEmpty to disambiguate
whether we are talking about an empty list or not. And this is
perfect, because if scrutinizing zeros had forced the evaluation of
that rightmost thunk, isEmpty would have diverged for reasons we’ll
understand soon.

When a constructor application is the outermost expression inside a


thunk, and we try to evaluate that thunk somehow, the constructor
application becomes apparent immediately, but not its payloads.
We say that the thunk, which held but mystery, has now been
evaluated to weak head normal form. And no, these are not words
brought together just for their cadence, although one must wonder
whether this was accident or design. Weak head normal form
means that only the head of this thunk, the outermost expression in
it, is guaranteed to have been evaluated. That’s all it means. And
being a weak head, of course, it won’t force its constituent thunks
to reveal themselves.

So there we have it. Gently, isEmpty was able to derive meaning


from intent, from the promise of a list made through types, from
the fact that it was (:) and not [] who revealed itself first. isEmpty
doesn’t need to know about the values in the list, so it doesn’t peek,
leaving the thunks unevaluated, preserving the list’s laziness.

Funnily, however, our application of isEmpty to zeros created yet


another thunk for a value of type Bool. So in reality, no evaluation
has taken place so far in this chapter. It has all been a lie. Sure, we
know to what extent isEmpty zeros would force the evaluation of
zeros in order to become False if somebody asks for this boolean
result, but nobody seems to be asking for this, so nothing is ever
evaluated.

It might help to learn how programs run once they have been
compiled. Essentially, every executable program has some sort of
magical entry point, a function, that will always be evaluated in full
so that the computer can find there the orders it will blindly follow.
So if we decide to use isEmpty zeros within this function, this would
force a Bool out of our isEmpty zeros thunk, which would in turn
force zeros to be evaluated to weak head normal form. But none of
this matters for the time being, we are not in a rush to run anything
anywhere, we are lazy, so let’s go back to our thunks.
95. Normal form
Let’s continue with the assumption that zeros has been evaluated to
the extent it needed to be evaluated in order for isEmpty zeros to
deliver its False result. That is, let’s assume that zeros is known to be
<thunk> : <thunk>.

zeros is in weak head normal form, for “cons” (:) is known, yet
acquiring this knowledge didn’t force the evaluation of any of the
thunks that are mentioned as its payload. But what about the
expression isEmpty zeros itself, known to be False? Is it also in weak
head normal form? Surprisingly perhaps, yes, yes it is, because
discovering False didn’t force the evaluation of any other thunk
within this constructor. Sure, there was never a thunk inside False
that could be evaluated to begin with, seeing how this constructor
has no room for carrying another expression as payload, but that’s
beside the point. Nevertheless, this scenario of an expression being
fully evaluated, like False, with no thunks in it at all, is curious
enough that it has its own name. Very confusingly, we say that
False is an expression in normal form, and this is in addition to its
being in weak head normal form.

In other words, in Haskell, the extent to which an expression has


been evaluated is one of two and a half alternatives. If the
expression we are considering is completely unevaluated, then it is a
thunk. Otherwise, it is an expression in weak head normal form.
That’s two. Now, expressions in weak head normal form may or
may not contain unevaluated sub-expressions. If they don’t, like
False, then we say the expression is in normal form too, beside being
in weak head normal form. That’s two and a half, isn’t it?

So, since our idea of infinity in zeros is hidden behind a thunk, as


long as we don’t evaluate that thunk to normal form, we’ll be
alright. An infinity in a box. Maybe just don’t tell Pandora about it.

The problem with sum is that in order to deliver results, it must


bring all of zeros into normal form. For didactic purposes, let’s look
at how this happens by going back observing our first
implementation of sum, the one that didn’t rely on monoids nor
folds. However, know that what we are about to see is true of other
versions of sum too.

sum :: [Natural] -> Natural


sum = \xs ->
case xs of
[] -> 0
x : rest -> x + sum rest

As before, we start with zeros as an unevaluated expression, a


thunk.

zeros :: [Natural]
zeros = <thunk>

We will assume something forces the evaluation of the thunk


resulting from saying sum zeros to weak head normal form. Which,
in this case, seeing as the result is a Natural number, will coincide
with its normal form too. That is, we are expecting the Natural
number resulting from sum zeros to be fully evaluated. Just a
number, no thunks.

When we apply sum to zeros, which inside sum we call xs, the first
thing that happens is that a case expression scrutinizes this xs in
order to decide where to go next depending on whether we
encounter [] or (:). This forces xs to be evaluated to weak head
normal form. Encountering [] means we are done, but in our case
we know this will never happen because the list is infinite and
there’s no [] in it, so we pattern match on x : rest instead. Up
until this point, zeros has been evaluated to <thunk> : <thunk>, just
like in isEmpty zeros. However, we are not finished yet.

Next, we have an application of (+) to a and a recursive call to sum


rest. Adding two numbers requires those numbers to be fully
evaluated to normal form. If you recall, back when we were
learning how to use foldr to implement sum, we found ourselves in a
situation where we weren’t able to perform our additions because
we only knew about one of the two numbers we wanted to add, so
we needed to wait until we could get an actual number to perform
the addition. We were, in other words, waiting for these two
parameters to be in normal form. Here, we are seeing this again. a +
sum rest wants both a and sum rest to be in normal form, to be
actual numbers free of thunks. Only then can a + sum rest itself
become a numerical value.

While we are being terribly obsessive with the order of evaluation of


our program, we should highlight that we don’t really know which
of these two arguments, a or sum rest, our function (+) will evaluate
first. We can discover this on our own, and we will learn how to do
that soon, but for now let’s profit from our ignorance.
Conceptually, it doesn’t matter whether we evaluate a or sum rest
first, because our program will diverge nonetheless. Eventually,
both a and sum zeros will need to be actual numbers in normal form
anyway. This can certainly happen for a, which is just 0, but it
won’t happen for sum rest. Why? Well, keep in mind that we are
already trying to evaluate sum zeros, for which we are forced to
evaluate sum rest. However, if we recall, our definition of zeros was
0 : zeros, so in this case rest is just another name for zeros. In other
words, we are saying that evaluating sum zeros requires evaluating
sum zeros. Thank you very much, that’s not helpful at all. We are at
a loss. At this point sum zeros depends on itself as much as undefined
did. It diverges. Had we evaluated a before sum rest, we would have
diverged nonetheless, but not before discovering the actual numeric
value of a, 0, in vain. In fact, even if we ignored a altogether, we
would still diverge. Let’s see how.
96. Spine
This is length, a function counting the number of elements in a list.

length :: [a] -> Natural


length = \xs ->
case xs of
[] -> 0
a : rest -> 1 + length rest

length doesn’t pay attention to the actual elements of type a in this


list. All length cares about is how many applications of (:) there are.
That’s all. Each time length encounters (:), it adds 1 to the result of
recursively applying length to the rest of the list. Using equational
reasoning, it’s easy to see how this works for a finite list like [9, 4,
6].

length [9, 4, 6]
== 1 + (length [4, 6])
== 1 + (1 + (length [6]))
== 1 + (1 + (1 + (length [])))
== 1 + (1 + (1 + 0))
== 1 + (1 + 1)
== 1 + 2
== 3

Indeed, 3 is the length of [9, 4, 6]. But what about the length of an
infinite list like zeros? How do we calculate it? Well, we don’t.
Intuitively, expecting a finite number measuring the size of an
infinite structure is kind of silly, isn’t it?

If you look hard enough, you’ll notice that the only difference
between sum and length is that whereas sum adds together the
elements of the list themselves, length adds a 1 instead, each time it
encounters an element. That’s all. In other words, it ignores the
elements themselves, it never tries to evaluate them, they stay inside
their thunks. Still, the use of 1 + length rest forces length rest itself
to be evaluated to normal form, which diverges just like sum rest
did, because given our defition of zeros as 0 : zeros, rest and zeros
are really the same. So length rest means length zeros, which is
exactly what we are failing to evaluate to normal form at the
moment, so our program goes into an infinite loop.

Anyway, the fact that length doesn’t try to evaluate the elements in
the list implies that length, contrary to sum, is not trying to force the
given list to normal form. Yet, both sum and length diverge. In other
words, it doesn’t take a normal form evaluation to have an infinite
structure blow up, all it takes is being strict enough, so be careful.

length is essentially uncovering the structure of the given list


without forcing the evaluation of the individual elements
themselves. length will force each and every use of (:) and [] to
their weak head normal form, but not the actual elements
contained in them. We call this structure, devoid of its content, the
spine of a list. Or, well, of any other non-list data type we might be
dealing with.

In other words, evaluating the spine of a list means discovering


whether its structure is [], [_, _], [_, _, _] or something else
without necessarily evaluating the elements in them.
97. Lazy enough
Being as strict as sum makes our programs diverge. Being a bit less
strict but still strict enough, as length, still doesn’t work. Being as
lazy as isEmpty seems to do the trick, but that function doesn’t do
much. Let’s see if we can find something more productive that can
cope with infinite lists.

head :: [a] -> Maybe a


head = \case
[] -> Nothing
a : rest -> Just a

head is a function that returns Nothing if the given list is empty, or


Just the first element of the list otherwise. Well, “first” might seem
unfair, since we know that lists start from [], and using (:) we pile
new elements on top of it. But here we really mean first in the Last
In, First Out sense of the stack of plates. So yes, head returns the first
element of the list, if any. The name “head” might be confusing,
considering we just talked about “weak head normal form” and the
like. But this is just is an accident, that head is unrelated to this head.
Feel free to mentally rename this function to “first”, “top”,
“outermost” or anything else that makes you happy.

Would head work with an infinite list like zeros? Well, let’s see. head
scrutinizes the given list so as to tell apart [] from (:), just like
isEmpty did. At this point, zeros has been evaluated to <thunk> :
<thunk>. Next, head completely disregards rest, which in the case of
zeros means just zeros. This is great. It means that we don’t have to
worry about the infinite zeros anymore, which suggests that yes,
head works with infinite lists. And what about a? Well, we just put
it inside another constructor, Just. This doesn’t force the
evaluation of a either. It simply preserves the evaluation state of a,
thunk or not, inside a new constructor. But even if this did force
the evaluation of a, head would still be able to cope with infinite
lists, since it’s never a in a : as who can make our programs diverge.
Well, except when a is undefined or similar, but why would it be?
head zeros, when evaluated, safely results in Just 0.
98. Equations
Alright, using head we are able to extract the first element of a list.
But lists can have more than one element in them, so in theory we
should be able to write a function that takes the first few elements
of a list, rather than just one of them. Let’s write this function, let’s
call it take.

take :: Natural -> [x] -> [x]


take = \n xs ->
case n of
0 -> []
_ ->
case xs of
[] -> []
x : rest -> x : take (n - 1) rest

Our implementation of take is rather ugly, aesthetically speaking.


Very, actually. We’ll take care of that soon, but for now let’s
content ourselves with the fact that it works as expected. take 3
zeros, say, returns a list with the three first elements of the list zeros,
that is, [0, 0, 0]. And of course, it works for non-infinite lists too.
For example, take 2 [5, 7, 4, 1] returns [5, 7]. If we ask for 0
elements, as in take 0 zeros, then we get an empty list [] as
requested. Let’s see how all of this works, and more importantly,
why.

Actually, no. No, no, no. This is just too ugly. Let’s clean it up
before trying to make sense of it.

If you recall, we said that foldr was able to cope with infinite lists,
so in theory we could rely on foldr to implement a fine looking
take. And yes, yes we could, but the solution would be a bit tricky
to follow, so maybe let’s try something else first. In Haskell, the
following two definitions of the id function are the same:

id :: x -> x
id = \x -> x

id :: x -> x
id x = x

That is, rather than binding the input value to the name x as part of
a lambda expression, we do it on the left-hand side of the equals
sign =. This is another syntax for defining functions, different from
the \… → … syntax we’ve been using so far. But mind you,
conceptually, from the point of view of the lambda calculus, id is
still a lambda expression, a function, and will be treated as such.
This is mostly just a syntactic difference, not a semantic one. And
why do we have two ways of defining functions? Well, it can be
convenient at times, we’ll see. We call these alleged cosmetic
improvements syntactic sugar. Haskell is sweet and sticky like that.

There are two interesting things about these equations. First, not
only can they bind expressions to a name, they can also pattern-
match on them. For example, let’s redefine that isEmpty function
from before, but this time using equations.

isEmpty :: [a] -> Bool


isEmpty [] = True
isEmpty _ = False

Ah, that’s nice. We are saying that if the input to this function is
the empty list [], we return True, and if it’s anything else, as caught
by the wildcard _, we return False. Just like in case expressions, the
different patterns are tried from top to bottom, and the first one
that matches gets to decide what happens next.

But perhaps more interesting, these equations allow us to bind and


pattern-match more than one input at a time, something that we
just can’t do with case expressions. Well, not directly anyway. Let’s
profit from this by implementing a better looking version of take.

take :: Natural -> [x] -> [x]


take _ [] = []
take 0 _ = []
take n (x : rest) = x : take (n - 1) rest

Sweet, sweet sugar. What take is doing is quite clear now. If the
given list is empty, we won’t be able to select any elements from it,
for there are none, so we just return another empty list [].
Incidentally, notice that as we completely ignored the first
parameter to this function, we didn’t force its evaluation. If it was a
thunk, it would still be a thunk.

On the second take equation we consider the case of the given


Natural being 0. If it is, then we are essentially being asked for a list
with no elements in it, so we can return [] without even having to
look at what’s in our second input parameter. Of course, in order
to compare this Natural number with 0, Haskell had to force it to
normal form behind the scenes. So, by the time we are done trying
to match against the pattern in this second equation, the Natural
number will have been evaluated to normal form and the given list
to weak head normal form.
Finally, if none of the patterns in the first two equations matched,
we move on to the final equation, in which we know that neither n
will be a 0 nor the given list will be empty, because we already dealt
with those cases before. So we proceed, confidently, to extract that
x from the input of the list, put it on the output list, and then
recursively call take asking for one less element from a list one
element shorter.

Using equational reasoning, we can see how take 2 zeros reduces to


[0, 0], for example.

take 2 zeros
== -- 3rd equation
0 : take 1 zeros
== -- 3rd equation
0 : (0 : take 0 zeros)
== -- 2nd equation
0 : (0 : [])
== -- Syntactic sugar
[0, 0]

Were you paying attention? Yes, [a, b, c] is also syntactic sugar, an


alleged aesthetic improvement for a : (b : (c : [])). But of course
we already knew this.

Anyway, take consumes just enough from the infinite zeros so as to


construct a list of length 2 as requested. After those two elements
are found, it finalizes the list by sticking a [] at the end, rather than
yet another recursive call to take as it had been doing so far.

Similarly, we can see how take 3 [4] has an early encounter with []
as we hit the first equation, even though 3 demanded more.
take 3 [4]
== -- 3rd equation
4 : take 2 []
== -- 1st equation
4 : []
== -- Syntactic sugar
[4]

Alright, take works. take takes a list, infinite or not, and consumes it
to the extent that it needs to do so without diverging. This is
already a useful achievement, but perhaps more importantly,
contemplate how this lazy consumption of infinite structures
allows us to keep the beautiful definition zeros as it is, reading like
poetry, and take too, with its striking straightforwardery. But the
real treat, actually, is how take lazily produces a list while lazily
consuming another one.

In our third equation, where take returns x : take (n - 1) rest,


what’s really happening is that we are constructing a new thunk
which when evaluated to weak head normal form will become x :
<thunk>, where x preserves the evaluation state it had on the original
list, thunk or not, and the thunk that shows up as the second
parameter to (:) defers the recursive call to take. Defers. That’s the
important bit. So, really, no work has happened here either. take,
on this equation, is taking a lazy list and lazily turning it into yet
another lazy list. It’s not until we actually evaluate the resulting lazy
list that take will do any work. So, for example, we could take the
seven hundred first trillion elements of an infinite list, and this
would be free as long as we don’t actually try to do something
concrete with these elements, such as adding them together with
sum.
So why is it that take succeeds where sum fails? Well, it really is quite
simple. While sum is essentially folding a list with (+), a function
that will force the evaluation of its inputs to normal form before
being able to produce an output, take, using (:), can produce its
output right away without having to force its payloads beyond
their current evaluation state. That’s all. This allows take to lazily
produce a list, which it does by lazily consuming another one. This
is the same laziness that allowed zeros to exist, together with a
myriad other beautiful constructions we’ll see later on.
99. Pattern much
Just like in case expressions, we can rearrange the order of patterns
in functions using equation syntax to some extent. However, we
need to be careful about two things. First, laziness. To illustrate
this, let’s rewrite and using this equation syntax.

and :: Bool -> Bool -> Bool


and False False = False
and False True = False
and True False = False
and True True = True

This looks cute, but it is actually wrong. The problem is the same as
before: and shouldn’t be trying to scrutinize its second parameter
until it has confirmed that the first one is True, because this forces it
into normal form, which will in turn make us do that trip to the
market, perhaps in vain. We need to avoid scrutinizing the second
Bool until we are certain we need it.

and :: Bool -> Bool -> Bool


and False _ = False
and True False = False
and True True = True

This works as expected. However, we are doing something silly. We


force this second Bool into normal form, we scrutinize it, only in
order to return a Bool with exactly the same value. Well, we might as
well return that same Bool without even looking at it.
and :: Bool -> Bool -> Bool
and False _ = False
and True x = x

That’s much better. So yes, laziness may be something for us to


keep in mind when deciding how and in which order we write our
patterns.

The second thing we need to consider when arranging our patterns


in equations or case expressions is whether they overlap which each
other, which may accidentally cause a pattern to catch the wrong
thing. For example, consider this rearrangement of the take
equations:

take :: Natural -> [x] -> [x]


take _ [] = []
take n (x : rest) = x : take (n - 1) rest
take 0 _ = []

Compared to our previous take, we swapped the order of the last


two equations. But now, the first and second equations alone will
catch all the possible combinations of inputs to this function.
Luckily for us, Haskell’s most kind compiler GHC will let us know
about this oversight during compile time. We can take a hint that
this new version of take is doing something wrong by realizing that
it will never force the evaluation of the given Natural value: Neither
binding it to a name such as n, nor using n as one of the arguments
in a function application like in n - 1, will force the evaluation of n.
Actually, we could even get rid of n and that last equation, and
things should behave exactly the same.
take :: [x] -> [x]
take [] = []
take (x : rest) = x : take rest

Do you recognize this new take? Pay close attention. That’s right,
it’s the identity function once again. So be careful about the order
in which you write your patterns, or you might end back where you
started.

Moreover, in case you didn’t notice, our broken take with its
equations rearranged leads to the silly situation of trying to apply n
- 1 even when n is 0, in which case the resulting value will not be a
Natural number, for there’s no natural number less than zero.
Unfortunately, this type-checks and the problem goes completely
unnoticed because the evaluation of this Natural never happens.
Sure, take is failing in other ways too, so hopefully that makes our
program collapse sooner rather than later, but we can’t guarantee
that. Nothing good can come out of this.
100. Types, please
There are two reasons why our broken take was trying to come up
with these non-existent “negative natural numbers”. One could be
seen as an accident, but the other one was the irresponsibility that
allowed the accident to take place.

The fundamental problem is in the type of (-), the function that


subtracts two Natural numbers and returns the result as yet another
Natural number.

(-) :: Natural -> Natural -> Natural

Now, if you recall, the smallest Natural number that can possibly
exist is 0. However, the type of (-) allows us to say things like 3 - 4,
where both 3 and 4 are perfectly acceptable Natural numbers, yet the
expected result, also of type Natural, can’t possibly exist. There is no
such thing as a “negative one natural number”, as 3 - 4 :: Natural
would want us to believe. This is the problem our wronged take
accidentally faced. But the culprit was not take, it was (-) who
enabled the accident in the first place. So let’s fix (-), let’s change its
type. Or maybe let’s keep (-) as it is, for reasons that will become
apparent later on, but let’s write a wrapper around it that will
perform the subtraction safely. Let’s call it safeSubtract, and then
let’s have take use it.

From where we are standing, the most evident solution would


probably involve changing the return value to a Maybe Natural, so
that Nothing is returned whenever the resulting Natural would be
nonsense. That is, we want safeSubtract to have type Natural →
Natural → Maybe Natural.
The implementation of safeSubtract is rather straightforward. All
we need to do is ensure that b is not bigger than a, as this would
result in a non-existent “negative natural number”. Alright, for this
task, let’s introduce a new infix function (<) of type Natural →
Natural → Bool, to be used as a < b, returning True whenever b is
bigger than a.

safeSubtract :: Natural -> Natural -> Maybe Natural


safeSubtract a b =
case a < b of
True -> Nothing
False -> Just (a - b)

So there we have it, safeSubtract will never return an invalid Natural


number because it always checks that subtracting a and b makes
sense before doing it. If it doesn’t, it just returns Nothing. How
would take make use of this function? Let’s see. Let’s start with a
sane take.

take :: Natural -> [x] -> [x]


take _ [] = []
take 0 _ = []
take n (x : rest) = x : take (n - 1) rest

Now let’s replace n - 1 with safeSubtract n 1.

take :: Natural -> [x] -> [x]


take _ [] = []
take 0 _ = []
take n (x : rest) = x : take (safeSubtract n 1) rest

But of course, this doesn’t type-check anymore because take takes a


Natural as its first argument, not a Maybe Natural as safeSubtract n 1
returns. So maybe we should pattern match on safeSubtract n 1
first, and only if we have a Just we recursively apply take.

take :: Natural -> [x] -> [x]


take _ [] = []
take 0 _ = []
take n (x : rest) = x : case safeSubtract n 1 of
Nothing -> []
Just m -> take m rest

Hey, look at that, it worked. And, actually, since this third equation
is already dealing with the fact that n might be 0, perhaps we can
drop that second equation altogether. Let’s see.

take :: Natural -> [x] -> [x]


take _ [] = []
take n (x : rest) =
x : case safeSubtract n 1 of
Nothing -> []
Just m -> take m rest

Hmm, no, that’s not quite right. For example, consider take 0 [5,
3, 8].

take 0 [5, 3, 8]
== 5 : case safeSubtract 0 1 of
Nothing -> []
Just m -> take m [3, 8]
== 5 : []
== [5]
That is, we are selecting the first element of our list before
scrutinizing safeSubtract n 1 to see if we were asked for any element
at all. Now, this is not necessarily a bad thing. Perhaps this is what
we wanted take to do. It is important to tell apart “mistakes” like
this one, where we are successfully repurposing a function, from
actual silly ideas such as allowing “negative natural numbers” to
exist. We said it before: At some point we need to tell the computer
what to do, and it’s not the computer’s responsibility to judge
whether we asked for the right thing or not. Of course, as much as
possible, once we know what it is that we want to solve, we want
the type-checker to help us achieve this and nothing else. However,
the type of take says nothing about its intended behavior, so in
return we don’t get any help from the type-checker and make
“mistakes”. But don’t let this scare you, because we can be precise
enough in our types so that it becomes impossible to write a
misbehaving take. We will get there. This book is all about that,
after all.

Anyway, next take. Let’s try to use safeSubtract before attempting


to construct the list and see what happens.

take :: Natural -> [x] -> [x]


take _ [] = []
take n (x : rest) =
case safeSubtract n 1 of
Nothing -> []
Just m -> x : take m rest

Ah, yes, this works as expected, just like our very first take. Is it
better? Well, no, why would it be? Improving take was never our
goal. Our goal was to make Natural subtraction safe, and that is all
we did.
And by the way, perhaps surprisingly at first, we could have
implemented safeSubtract as follows:

safeSubtract :: Natural -> Natural -> Maybe Natural


safeSubtract a b = bool (Just (a - b)) Nothing (a < b)

This works just fine because even if it looks like we are trying to
subtract a - b right away, in reality, due to the laziness of bool, this
subtraction doesn’t even happen unless it is a < b is known to be
False. Ultimately, this is why we cherish laziness. It’s not so much
about the lazy lists nor the other lazy structures, but about how
expressive and ergonomic our programming experience becomes
when we don’t have to worry about when something will be
executed. We write our expressions optimistically, and leave it up to
Haskell to figure out if and when they deserve execution. It’s so
comfortable that we sometimes forget this even exists, even after it’s
taken over our ways.
101. Closure
Adding two natural numbers results in another natural number.
Multiplying two natural numbers results in another natural
number. Subtracting two natural numbers, however, does not
necessarily result in another natural number. Specifically,
subtracting a - b results in a natural number only if a is greater
than, or equal to, b. There is a pattern here, this is not an accident.

When an operation on one or more values of a particular type


results in yet another value of that same type, we can say that this
type is closed under this particular operation. For example, the
natural numbers are closed under addition and multiplication, but
they are not closed under subtraction. They lack this property.

Monoids too, for example, are closed under their mappend operation
of type a → a → a, for some choice of a such as Sum or [x].

So what happens when we subtract Natural numbers, seeing as they


are not closed under subtraction? We can address this question
from many perspecitves. For example, we can say that Nothing
happens. That’s what we did before. But, in reality, we “know” that
subtracting 3 - 4, say, results in -1. So where does that -1 come
from? The naturals find closure under subtraction in the integer
numbers, which are the naturals together with their negative
counterparts. In Haskell, integer numbers have type Integer. This is
the type of -1.

So perhaps what we want, actually, is for safeSubtract to have type


Natural → Natural → Either Integer Natural. That is, return a Natural
if possible, or an Integer otherwise.

Really? I don’t think so. We just said that the integer numbers
include all of the natural numbers plus their negative counterparts.
In other words, we are saying that the naturals are a subset of the
integers, meaning that rather than having Either Integer Natural,
artificially segregating the natural subset of the integers in this sum
type, maybe we could just use Integer as the return value of
safeSubtract, as Natural → Natural → Integer. We could, we could.
However, since we are now returning Integers, we might as well
take Integers as input so that we can do things such as safeSubtract
-3 7. What we really want is a function of type Integer → Integer →
Integer that works perfectly fine because the integer numbers,
contrary to the naturals, are closed under subtraction. Of course, if
now we want to subtract Naturals through this function, we’ll need
to convert them to Integers first. That’s easy, though, considering
how naturals are a subset of the integers, meaning that any Natural
can be represented as an Integer too. In fact, Haskell comes with a
function toInteger of type Natural → Integer that does just this.

By the way, for very superficial parsing reasons, in Haskell we can’t


actually write safeSubtract -3 7. However, we can say safeSubtract
(-3) (-7), with those extra parentheses, or even safeSubtract (negate
3) (negate 3), to achieve what we would expect. Anyway, not
important.
102. Num
Actually, we can get rid of the name safeSubtract and use (-)
directly to subtract Integer numbers. There’s nothing that could be
characterized as “unsafe” regarding the subtraction of integer
numbers, so we might as well use the shorter infix name -, which
we can do because the type of (-) is not Natural → Natural → Natural
as we said before.

(-) :: Num x => x -> x -> x

The polymorphic type of (-) says that you can subtract values of
types for which there is a Num instance, such as Integer and Natural.
So yes, we can use (-) to subtract integer numbers too.

Num is one of the ugly kludges that we have in Haskell as of the


beginning of the third decade of the third millennium. We
witnessed this before, when (-) promised to be able to subtract two
natural numbers without leaving room for a potential failure,
which we know was a lie. Luckily for us, we can mostly ignore Num
and nonetheless be fine. Contrary to mathematical operators in
many other languages, baked in as those booleans from before, Num
and operators like (-) are just user written code that happens to be
shipped together with the language, which we can choose not to
use. We could, for example, define a closed (-) only for types where
it makes sense, excluding Naturals. Will we ignore Num in this book?
Not entirely, but we will learn how to do so if we so desire, of
course.

Something we should highlight before not paying much more


attention to Num throughout the rest of this book is that when we
say 3 or -4, for example, the type of these expressions is neither
Natural nor Integer, but rather Num x ⇒ x. For example, 3 is a value
constructor meaning “the number three”, which can be used to
construct a value of any type that implements an instance for the
Num typeclass. It is implemented as follows: Haskell magically
converts your digits into an Integer, and then further magic applies
fromInteger :: Num x ⇒ Integer → x to that Integer, where
fromInteger is one of the methods we get to implement as part of the
Num typeclass. On the one hand, this is quite clever. On the other
hand, in the Num instance for Natural numbers, say, we are forced to
implement the method fromInteger with type Integer → Natural.
Really? What would be the answer to fromInteger (-4), say? There’s
no right answer. You see, a kludge. There are nice models for
understanding what a number is, and we’ll see some, but Num is not
one of them. Num is why programmers cry.
103. Too eager
One could argue that take should return Maybe [x] rather than [x],
so that the caller gets a Nothing rather than a shorter list when the
number of elements in the input list is less than requested. Indeed,
one could argue that, but it would be in vain. Let’s see why.

takey :: Natural -> [x] -> Maybe [x]


takey 0 _ = Just []
takey _ [] = Nothing
takey n (x : rest) =
case takey (n - 1) rest of
Nothing -> Nothing
Just xs -> Just (x : xs)

Our new takey delivers the result it promises, and even deals with
infinite lists just fine. So what’s the problem? What’s happening is
that in takey's third equation, before making use of the lazy
constructor (:), we are forcing the evaluation of takey (n - 1) rest
by scrutinizing it through a case expression. Otherwise, how would
case know whether to return Just or Nothing without first learning
whether Just or Nothing is the result of the recursive call to takey
itself?

takey took the laziness take had away, for take never had to
scrutinize its tail in order to construct a list with an x and a mere
promise that there could be more xs, thus preserving the list’s
laziness. Remember, a list doesn’t really need to know about its
contents, not even when it’s being constructed. It is only when we
try to observe it beyond its weak head normal form that we start
forcing secrets out of its thunks.
And why do we care about preserving laziness? Well, that’s the
wrong question. The right question is: Given that lists can be
produced lazily, allowing lazy consumptions to be performed
efficiently at a later time, if at all necessary, why wouldn’t we allow
so? We don’t know what the future may call for, nor what this
laziness may allow. We shouldn’t arbitrarily restrict things just
because we can. Not unless we can justify these constraints.
104. Eq
Many times, though, we need to be certain that our list has an exact
number or elements in it. But even in those cases we may want to
keep the core functionality of take as it is, and use it in combination
with another function like length to ensure that the obtained list is
of a particular length. Generally speaking, we’d rather avoid this
because there are data structures other than lists that are more
efficient at knowing their own lengths. Remember, a list must
iterate itself completely to learn its length, it must uncover its spine,
which is certainly a more expensive computation than just reading a
number somewhere saying “oi, it’ll be one-thousand seventy-five
alright, the length”. Alternatively, we could modify lists so that they
carry this length information with them somehow, and we will do
so later on, it will be fun, but for now let’s explore this whole idea
using our boring and lazy linked lists.

takey :: Natural -> [x] -> Maybe [x]


takey n xs =
case take n xs of
ys ->
case length ys == n of
True -> Just ys
False -> Nothing

We are using the first case expression just to give take n xs a name,
as we’ll be using it twice afterwards. Whatever take n xs may be,
we’ll call it ys. Then, we are checking whether the length of ys
equals n as requested. When this is True, we return ys wrapped in
Just. Otherwise, Nothing.

We are using the infix function (==) for the first time here. This
function returns a Boolean value indicating whether it is True or
False that its two arguments, here length xs and n, are equal.

Scrutinizing the result of length ys == n to check whether this is


True or False forces the evaluation of this expression to its normal
form, which in turn forces length ys to normal form, which itself
forces yn to reveal its spine, losing its structural laziness. This is
where most of the laziness is gone. Its elements remain a mystery,
though.

This (==) is actually defined as a method of a typeclass called Eq.

class Eq (x :: Type) where


(==) :: x -> x -> Bool
a == b = not (a /= b)

(/=) :: x -> x -> Bool


a /= b = not (a == b)

{-# MINIMAL (==) | (/=) #-}

Ah, some new noise trying to distract us. Let’s take this step by
step. First, the high-level overview. Eq is a typeclass for Types with
two methods in it, just like the Monoid class from before. One named
(==) and the other (/==). However, there’s also a pragma, a special
instruction that the authors of Eq wrote for the compiler, that says
when we implement an Eq instance for a type of our choice, we
don’t really need to implement both methods. Rather, we can get
by implementing only the minimum requirements. Namely, either
(==) or (/=). That is what the {-# MINIMAL (==) | (/=) #-} pragma is
saying. Why, though?

Contrary to typeclasses we’ve seen before, both (==) and (/=) come
with default definitions that will serve as the implementation of
these methods for the instances of Eq in which we have chosen not
to override some of these methods. In particular, a == b is defined
to be not (a /= b), and vice-versa.

not :: Bool -> Bool


not True = False
not False = True

not negates a boolean value. not True is False, not False is True. So
what a == b = not (a /= b) is saying, concretely, is that comparing a
and b for equality using a == b equals the negation of a /= b, which
suggests that a /= b tells us whether a and b are different, rather
than equal. And, indeed, if we look at the default definition of a /=
b as not (a == b), we can see that this conveys the idea of a and b not
being equal.

What’s interesting about these two functions is that they recursively


depend on each other. If we tried to evaluate a == b or a /= b as
they are, without changing the definition of at least one of (==) or
(/=) in the relevant Eq instance, our program would diverge, for a ==
b would depend on a /= b which would again depend on a == b,
creating an infinite loop. This is why the authors added that MINIMAL
pragma to the typeclass: It causes the compiler to complain if we
fail to define at least one of (==) or (/=) explicitly.

As for why equality (==) and non-equality (/=) are both part of this
Equality typeclass: It is mostly a matter of convenience. Sometimes
it’s easier or faster to decide that two things are equal, while other
times it’s easier to notice that they are different. We are studying
this Eq because it gives us an opportunity to showcase the role of
default method definitions and MINIMAL pragmas in typeclasses, but
conceptually, we could have Eq, (==) and (/=) defined this other
way, and it would have been enough:

class Eq (x :: Type) where


(==) :: x -> x -> Bool

(/=) :: Eq x => x -> x -> Bool


a /= b = not (a == b)

That is, we only kept the (==) method in the Eq typeclass —without
a default definition, because there’s not one definition that could
possibly work for all choices of x— and we converted (/=) into a
function that simply negates whatever (==) says. The Eq x
constraint on (/=) requires that there be an Eq instance defined for
the chosen x. Otherwise, without it, we wouldn’t be able to say a ==
b within the definition of a /= b.

We used a strange syntax this time to define our infix operators, but
there’s nothing special going on beyond a high dose of syntactic
sugar. All the following mean the same thing:

a == b = not (a /= b)

(==) = \a b -> not (a /= b)

(==) a b = not (a /= b)

(==) a = \b -> not (a /= b)

Well, operationally, there might be some difference between these


definitions, but we don’t care about that in this book.
105. Lazy mapping
Much like take, fmap transforms a list lazily. This is quite easy to see
if we look at an implementation of fmap.

fmap :: (x -> y) -> [x] -> [y]


fmap _ [] = []
fmap f (x : xs) = f x : fmap f xs

When the given list is empty there’s nothing to transform, so we


just return another empty list. But if there is at least one element x
in the list, as witnessed by the (:) constructor, we return another
list with f x as its head and fmap f xs as its tail. Yeah, among friends
we call the second argument to (:) its “tail”. Picture a snake with a
head, and then a long, long tail. Now, what’s important to keep in
mind here is that (:) is not forcing the evaluation of its payloads f x
and fmap f xs. All this function ever outputs, if forced to weak head
normal form at all, is <thunk> : <thunk>. That is, it defers the
transformations to the list, preserving its original laziness if any.
Promises, just promises.

The type of the list changes right away, though. We are always eager
to know the types of expressions, even if they don’t exist yet. This
makes complete sense, considering how the type-checker knows
nothing about the evaluation of expressions, so it couldn’t possibly
care about whether they have been evaluated or not. Types are
types, expressions are expressions, and they have different concerns.
Well, kind of. There will come a time when we’ll blur that
boundary too, but it won’t be today.

So yes, fmap is also one of those functions that lazily produces a list
while lazily consuming another one. It could choose not to do so,
but what would be the point of doing that? It’s only when
somebody needs to observe one of the elements of the produced list
that the application of f will be evaluated. Only when one needs to
iterate over it will its tail be uncovered insofar as necessary.

Can we fmap infinite lists? Sure we can, why wouldn’t we? Infinity
is not an alien concept in Haskell, it’s reasonable to expect things to
work perfectly fine with infinite structures most of the time, unless
something in their description suggests otherwise. For example,
here is an infinitely long list of eights, obtained by replacing each
element in the infinitely long zeros with an 8.

eights :: [Natural]
eights = fmap (const 8) zeros

We can use eights in any way we could use zeros.


106. Naturals
The natural numbers, we said, are the zero or a natural number plus
one. The zero or a natural number plus one.

the zero or a natural number


↓ ↓
naturals = 0 : fmap (\x -> 1 + x) naturals

plus one

This funny-looking code works just fine. Well, except for the
pointy labels which are there just to make a point. Ignore them.
naturals, of type [Natural], is indeed an infinite list of natural
numbers. Every natural number that exists is somewhere in this list.
That is, naturals gives us a never ending list starting with 0 : 1 : 2
: 3 : ….

Before trying to understand how naturals works, let’s talk about


unimportant superficial matters. In the definition of naturals,
rather than saying \x → 1 + x, we can say (+) 1 to make things a bit
cleaner. This is just a partial application of (+), in prefix form, to its
first parameter 1. We’ve seen this before.

naturals :: [Natural]
naturals = 0 : fmap ((+) 1) naturals

This, I’m told, is a bit easier on the eyes. And, well, as long as we are
cleaning things up, we could also partially apply (+) to 1 in infix
form instead, as (1 +). Notice how + is not isolated in its own pair of
parentheses anymore. With this syntactic sugar, saying (1 +) x is the
same as saying 1 + x or (+) 1 x. That is, the operand that appears
partially applied to the left of + will remain on the left once (+) is
fully applied to its two arguments. Alternatively, we can partially
apply the operand on the right as (+ 1), which when used as (+ 1) x
will preserve 1's rightful place as x + 1. In the case of addition, a
commutative operation, it doesn’t matter whether we say (+ 1) x or
(1 +) x because the result is the same either way. But this syntactic
sugar works for any infix operator, and the order of the arguments
might make a difference for them. For example, compare (x :) xs
and (: xs) x, both meaning x : xs. The order of the arguments to
the list constructor (:) does matter.

naturals :: [Natural]
naturals = 0 : fmap (1 +) naturals

Cute. Now we can go back to important matters. We can use


equational reasoning to see how naturals produces all of the Natural
numbers. Let’s do it step by step, it will be tricky this time. We start
by inlining the definition of naturals.

0 : fmap (1 +) naturals

And then we inline naturals once more.

0 : fmap (1 +) (0 : fmap (1 +) naturals)

Now, in our most recent definition of fmap, we said that fmap f (x :


xs) equals f x : fmap f xs. That is, we can apply f directly to the
first element and move the fmap application to the tail of the list. We
say fmap distributes the application of f over all the elements of the
list. We can use this understanding to modify our outermost fmap
(1 +) (0 : …) so that it becomes (1 +) 0 : fmap (1 +) …, or its less
ugly version where we reduce (1 +) 0 to just 1.

0 : (1 : fmap (1 +) (fmap (1 +) naturals))

Excellent. Let’s bring back memories, now. Do we remember the


composition law of Functors, the one which said that fmap g (fmap f
xs) is equal to fmap (compose g f) xs? We can use this law to clean
things up. Rather than saying fmap (1 +) (fmap (1 +) …), we can say
fmap (compose (1 +) (1 +)) …, thus removing one fmap application,
making things simpler to observe.

0 : (1 : fmap (compose (1 +) (1 +)) naturals)

We know function composition all too well. We now that compose g


f x applies f to x first, and g to this result afterwards. In our case, g
and f both add one, meaning that compose (1 +) (1 +) x will add 1
to x, and then it will add another 1 to that result. In other words,
compose (1 +) (1 +) x adds 2 to x. We will go ahead and replace all of
compose (1 +) (1 +) with (2 +). You may want to write down the
equational reasoning that shows that compose (1 +) (1 +) in fact
equals (2 +). We won’t do it here.

0 : (1 : fmap (2 +) naturals)

At this point we don’t have much to do but inline the definition of


naturals, so we do that.

0 : (1 : fmap (2 +) (0 : fmap (1 +) naturals))

As before, we can distribute the application of (2 +) in fmap (2 +)


(0 : …) as (2 +) 0 : fmap (2 +) …). We do that, and reduce (2 +) 0
to just 2 as well.

0 : (1 : (2 : fmap (2 +) (fmap (1 +) naturals)))

And once again, we can apply the Functor composition law to


simplify things a bit.

0 : (1 : (2 : fmap (3 +) naturals))

We could repeat this process over and over again, but I trust seeing
the first handful of Naturals come to be is more than enough proof
that naturals in fact contains an infinite amount of Natural
numbers in it, all of them, starting from 0 and incrementally
growing by one. There’s nothing in our reasoning suggesting we
will ever stop lazily producing new numbers.
107. Cavemen
So far we’ve been using our brain, like cavemen, to understand
when things are evaluated. We haven’t had any help from the type
system, we’ve been on our own. This is sad. There are ways to
encode laziness in our types. For example, we can have a strict
language, one that fully evaluates everything as soon as possible, but
still allows us to mark some things as “lazy” when necessary. In this
hypothetical language, we can imagine lazy lists being defined as
follows:

data List a
= Nil
| Cons (Lazy a) (Lazy (List a))

It this language, constructor payloads are strict by default, but Lazy


x defers the evaluation of x until somebody removes the Lazy
wrapper somehow. For example, using a function evaluate of type
Lazy x → x provided by the language itself.

Our hypothetical language could also force the evaluation of a and


b in an expression f a b before allowing f to even attempt to do
anything with a and b. Unless, of course, a or b are wrapped in that
Lazy type constructor, in which case their evaluation will be delayed
until explicitly requested. For example, we could define and as
follows, somewhat suggesting that the second input parameter
won’t be evaluated right away —although it doesn’t really say that,
does it?

and :: Bool -> Lazy Bool -> Bool


So why don’t we do this? Well, actually, some languages with a type
system as rich as Haskell’s do it. Haskell’s lazy-by-default nature is
the exception, rather than the rule. Although we’ll be glad to know
that at the flip of a switch we can make the Haskell code we write
be strict by default if we want to. And we can implement this Lazy
idea, too.

But just because we can do this, in Haskell or otherwise, it doesn’t


mean we should. The thing to keep in mind is that while types such
as Maybe x convey the semantics about what something is, a type
such as Lazy x talks about when x should be. We are conflating in
the type system meaning with execution, which is exactly what we
generally want to avoid. Should we not do this, then? Well, we are
not saying that either. Maybe we should. Mandating a strict order
of evaluation of our program, whether this shows up in the types or
not, could make its computery performance easier to reason about.
Do we want to reason and worry about this, though? Shouldn’t the
computer figure out when it is more convenient to do something,
enabling us to instead focus on what our programs should do,
blissfully oblivious of these operational details? So many questions,
so few answers.

It’s unclear what’s the right default approach, they each have their
virtues and shortcomings. We’ll talk about Haskell’s shortly. But
generally speaking, even if for a particular problem we’d prefer to
have a different evaluation strategy, that doesn’t mean that we need
to change the default evaluation strategy of the entire language. We
can usually override the defaults on a case by case basis. For
example, we might want to define a strict list, one where evaluating
the list to weak head normal form will force the evaluation of its
constituent parts to weak head normal form too.
data List a
= Nil
| Cons !a !(List a)

You see those exclamation marks preceding the types of the


payloads in Cons? Those tell Haskell that when evaluating a value of
type List a to weak head normal form, these payloads themselves
will have to be evaluated to weak head normal form too. Otherwise,
without the exclamation marks, the ones we friends call “bangs”,
these payloads won’t be evaluated unless explicitly requested by
somebody consuming the list, which is how we’ve been using lists
so far. Of course, whether the a itself contains unevaluated
expressions is a different matter that will need to be addressed too.
This definition of List implies, among other things, that it is not
possible to use Cons to define an infinite list in the same way we
used (:) to define zeros or naturals, because as soon as something
attempts to evaluate Cons to its weak head normal form, this will
trigger yet another evaluation of itself, which will trigger another
one, and another one, and another one, leading us to an infinite
loop.

Similarly, we can have functions force the evaluation of their input


arguments to weak head normal form too, even when not
necessary. For example, consider the const function from before:

const :: a -> b -> a


const a _ = a

This function completely ignores its second input parameter b, so


evaluating const a b won’t force b beyond its current evaluation
level. If b is a thunk, say, it stays a thunk. This makes sense. Why
would we evaluate b if we don’t need to? Yet, if we add but a single
bang, the story changes completely.

const :: a -> b -> a


const a !_ = a

This function still doesn’t use its second input parameter. Yet, if we
ever try to evaluate the result of const a b, then b will be evaluated
to week head normal form too. This function exists in Haskell, it is
called seq, and it is not as useless as it seems. Its arguments,
however, are in different order.

seq :: a -> b -> b


seq !_ b = b
108. Clingy
The quintessential example of why forcing the evaluation of some
value to weak head normal form is necessary, even if not really
necessary, is foldl. It turns out that the implementation we gave for
it is broken in a curious way.

foldl :: (z -> a -> z) -> z -> [a] -> z


foldl = \f acc as ->
case as of
[] -> acc
a : rest -> foldl f (f acc a) rest

The problem with this implementation is that on each iteration of


foldl, our use of f acc a to improve the accumulator acc creates a
new thunk that won’t be evaluated until we reach the end of the
list. In principle, this sounds appealing, but there is a problem that
has to do with computer resources. Values occupy space in
memory, values such as the inputs to f, one of which happens to be
a thunk that the previous iteration created. So if new thunks, which
themselves occupy memory, cling to these previous thunks that
already occupied memory, Haskell won’t have the opportunity to
reclaim any of this memory until the result from the entire
execution of foldl is evaluated. In other words, as foldl iterates over
the list, it demands more and more memory. And if this goes on for
long enough, our computer will run out of memory. All this for no
signifcant gain, because contrary to foldr, foldl is incapable of
producing an output as it lazily consumes a list. It must consume
the list entirely before being able to produce something.

So yes, foldl is way too lazy in the way it produces its output.
Ironically, it achieves this by being overly clingy while also being
way too strict in the way it consumes its input, which prevents it
from working with infinite lists at all. Way to go, foldl.

How do we fix it? Well, unsurprisingly I hope, all we need to do is


force the evaluation of the thunk that f acc a creates before making
a recursive call to foldl. Or, looking at it from a different
perspective, we need to make sure that acc has been evaluated to
weak head normal by the time we get our hands on it. In this way
we can be certain that we never create a thunk that depends on yet
another thunk that foldl itself created. How do we achieve this?
Well, as we did in seq, we just precede acc with a bang ! right where
we bind its name. That’s all.

foldl :: (z -> a -> z) -> z -> [a] -> z


foldl = \f !acc as ->
case as of
[] -> acc
a : rest -> foldl f (f acc a) rest

With this one change we are preventing foldl from creating more
thunks that it needs, thus reducing its memory consumption. This
strict, unclingy version of foldl, is actually called foldl' in Haskell,
and we should almost always use it instead of the way too lazy
foldl, which is only useful if f happens to be lazy in its first
argument, but it almost never is. The choice is usually between
foldr and foldl', rarely is foldl worth considering. It’s a shame the
most beautiful name foldl is wasted. Foldl prime though —that’s
how we prounounce foldl'— has a rather heroic ring to it, so we’ll
take it.

In practice, it turns out that worrying about things being too lazy is
more important than worrying about them being too strict. Mostly
because when things are too strict, we experience divergence in
some form right away. But with an overly lazy program, we may
not immediately notice what may cause our system to collapse later
on, once it has more data to process. There is a trick to avoiding this
situation. Perhaps we shouldn’t talk about it because, after all, this
is not a book about tricks, but here it goes anyway just in case.
When writing a function like foldl which uses some kind of
accumulator, we always make that accumulator strict. We bang
that acc. And when defining a new datatype, we bang each field in
its constructors too. We’ll have opportunities to repent and make
things lazy later on if we realize they needed to be lazy after all, but
by default we make them strict just in case. That’s it. Our program
continues to be lazy nonetheless because the non-accumulating
inputs to our functions continue to be lazy, and by far they are the
majority of what we write.

Anyway, as long as we are still cavemen, let’s learn how to measure


laziness using sticks and stones.
109. Troy
Do you remember how undefined, our bottom, our ⊥, always made
our program diverge whenever we approached it? A divergence that
could manifest itself as our program either crashing or entering an
infinite loop? Well, in this divergence we’ll find some help.

Haskell’s lazy evaluation strategy means that all expressions,


including silly things such as undefined, will only be evaluated when
necessary, never before. So, as if horses in Troy, we gift undefineds to
our functions and wait. If our program diverges, then our undefined
was evaluated. If it doesn’t, then it hasn’t. Of course, we only
experiment with this during the development of our program, if at
all necessary, wearing lab coats and gloves. Once we have confirmed
that the lazy behavior is the one we expected, we can communicate
the lazy semantics of our programs quite clearly. For example, in
the human-friendly documentation for and, we can say that when
its first input parameter is False, then the expression given as second
parameter will not be forced to abandon its cozy thunk, if any, and
we will get a proper non-diverging value as result.

and False ⊥ /= ⊥

Notice the /= sign, conveying the idea that the things to its sides are
different. We tend to write “⊥” because it’s not only undefined who
embodies divergence, and we don’t want people to make
assumptions about this. In every other case, and will need to
scrutinize both input parameters, both of these thunks, which will
cause and to diverge if any of the parameters themselves diverges.
and True ⊥ == ⊥
and ⊥ x == ⊥

In practice, these cases are not worth highlighting since they are the
rule, rather than the exception. Of course we can expect things to
collapse if we irresponsibly sprinkle bottoms here and there, so we
only ever talk of how functions like and are extraordinary, not of
how they are not. And what makes and special is that it doesn’t
always make use of all its inputs, so that’s what we talk about.

Using this notation, we can explain the difference between const


and seq. Well, flip seq actually. Remember, the order of their
arguments was flipped.

const x ⊥ /= ⊥
flip seq x ⊥ == ⊥

We can also show how merely constructing a list containing


bottoms using (:) doesn’t result in ⊥:

⊥ : ⊥ /= ⊥

How length doesn’t evaluate the elements of a list:

length [⊥] /= ⊥

Or how head doesn’t touch its tail.

head (x : ⊥) /= ⊥
How do we try these things, though? Are we supposed to compile
bottomful programs, run them, and wait for them to explode? Not
quite, not quite.
110. Frogs
Haskell, or GHC to be more precise, the Haskell compiler whose
acronym doesn’t officially stand for “Glorious Haskell Compiler”,
comes with a REPL, a read-eval-print loop. Acronyms, right? At
least if we repeatedly say “REPL” out loud we get to sound like a
frog.

A REPL is an interface we use to experiment with our language


interactively. We type in some expressions in it, like 2 + 3 or length
[True], the REPL reads them, evaluates them, and finally prints a
corresponding result back to us before starting this loop again.
Mind you, by “print” we actually mean displaying some text on our
screen. It’s called GHCi, this REPL.

> True
True :: Bool

> fmap not [True, False, False]


[False, True, True] :: [Bool]

> length [id, undefined]


2 :: Natural

The lines with a leading > are lines we typed manually in GHCi, and
below each of them we see the feedback from the REPL. We didn’t
need to type the > ourselves, though, that was our prompt. As soon
as we open GHCi, we are welcomed with something along the lines
of the following, and we can start typing expressions right away.

Welcome to GHCi. Type :? for help.


>
Ay no, a distraction. We can’t help it, we are really curious, we
anxiously type :? as suggested. That’s not a Haskell expression, but
GHCi understands it nonetheless and displays some help about this
interactive interface. We do that, and funnily, :? reveals something
interesting that might come in handy. The help mentions a magical
command, :sprint, that promises to display expressions only to the
extent that have been evaluated. It sounds terribly inconsequential
and fun, so we try it.

> xs = [undefined, undefined]

> :sprint xs
xs = _

> length xs
2 :: Natural

> :sprint xs
xs = [_, _]

Interesting. We can observe how merely defining xs creates a thunk,


here represented with _, and how applying length to xs forces it to
reveal its spine without attempting to evaluate any of the elements
in the list. Of course, actually evaluating the elements, for example
by typing sum xs in the REPL, will cause our program to diverge
because of the undefineds that we deliberately put inside our list.

> xs
*** Exception: Prelude.undefined

Ah, yes, catastrophe. We are lucky enough to get an error message


saying “undefined” somewhere in it, which proves our Trojan
point. These REPLs are quite an interesting tool for playful
exploration. We will use them quite frequently, mostly to prove
ourselves wrong.

Actually, on that note, as we continue interacting with our REPL


we’ll discover that the “E” in “REPL” is terribly overrated. We’ll
rarely evaluate things, for evaluation is about computing, and not
so much about meaning. We’ll mostly use the REPL to type-check
expressions, to discover new types, to see if we can compose this
and that. By far, the most commonly used GHCi command in the
REPL will be :type, or :t for friends. This command can tell us the
type of any expression without evaluating it.

> :t True
True :: Bool

> :t Just
Just :: a -> Maybe a

> :t Nothing
Nothing :: Maybe a

> :t (:)
(:) :: a -> [a] -> [a]

This is quite useful. We can toy around with :t to see if the


expressions we are trying to write have the types we expect them to
have. Of course, it gets more interesting with more complex types.
> :t (:) 3
(:) 3 :: Num a => [a] -> [a]

> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b

> :t fmap Just


fmap Just :: Functor f => f a -> f (Maybe a)

Another important GHCi command is :kind!, with that bang at


the end for no important reason. :kind! allows us to explore the
kinds of types. So, naturally, it expects a type rather than an
expression as input.

> :kind! Bool


Bool :: Type

> :kind! Maybe


Maybe :: Type -> Type

> :kind! Either


Either :: Type -> Type -> Type

> :kind! Either Bool


Either Bool :: Type -> Type

I suppose RTKPL, after read-type-kind-print loop, just wasn’t a


catchy enough acronym.
111. Dialogue
Something happened, something shocking. We didn’t tell GHCi
the types of our expressions. On the contrary, we were told their
types. GHCi inferred this. Well, Haskell did. Type-inference is a
fundamental feature of the Haskell programming language. We’d
be at a loss without it, we’d have to think a lot more.

> True
True :: Bool

> 3 + 4
7 :: Num a => a

Here we are not explicitly saying that True is of type Bool, yet Haskell
realizes this and shares this fact with us. Neither are we saying
whether 3 + 4 is an Integer or something else, yet Haskell reminds
us that 3 + 4 is actually a polymorphic expression, and that the
resulting 7 could be a value of any type a for which there exists a Num
instance. Lucky us. Of course, if we are not satisfied with this
polymorphism, we can force Haskell to assign a particular type to
the expression if we so desire by explicitly using :: as we’ve done
many times before.

> 3 + 4 :: Integer
7 :: Integer

The polymorphism is gone, we have a plain old Integer now. This


works because all we did was make the type inferred by Haskell a
bit more specific, without contradicting it. This is fine. However,
what’s more interesting is what happens when we do contradict the
inferred types in an incompatible way, when we get our types
wrong.

> 3 + 4 :: String
<interactive>:2:1: error:
• No instance for (Num String) arising from a use of ‘+’
• In the expression: 3 + 4 :: String
In an equation for ‘it’: it = 3 + 4 :: String

Fascinating. No instance for Num String arising from a use of + in the


expression 3 + 4 :: String. We couldn’t ask for a better error
message. Here the type-checker is telling us the exact problem. We
used the function (+) in the expression 3 + 4, and we told the type-
checker we wanted this to be a String. However, the type of (+), Num
a ⇒ a → a → a, requires that String, our a, be an instance of Num. But
String is no Num, so type-checking fails and we get a lovely type-
checker error message instead. From here, we can reason about how
to change our expressions or types to remedy this situation. Typing
our programs is a collaborative effort between us and the type-
checker, a dialog. We are never alone in this.

Haskell, as much as possible, will infer the types and kinds of our
expressions. We can write entire programs without giving a single
explicit type annotation, tasking Haskell with inferring the type of
each and every expression on its own. This works. However, it is
also a terrible idea. As fallible beings with limited time and capacity,
we need to see the types written down if we are to have any realistic
hope of efficiently understanding what goes on in our programs
and how to evolve them, recognizing common patterns in them as
we go. Remember, our programs are rarely as special as we think
they are, so the earlier we find structure in them, the better off we’ll
be. Let’s do a small experiment regarding this. Say, what does this
program do?

dog = fmap fmap id const seq (3 +) flip const seq True flip

Oh là là, c’est magnifique. What a unique, complex program.


Granted, we are riding the hyperbole here, trying to make point.
But, considering how ultimately, when viewed through the austere
eyes of the lambda calculus, programs are just functions and
applications of more functions and more applications, this example
is not that unrealistic. Now, Haskell’s type-inference machinery
will do an outstanding job at telling us that the type of this
expression is that of the identity function, which has but one
possible behavior. But, in light of this clarity, wouldn’t it have been
easier for us to be able to look at just one line of code saying a → a,
and in the blink of an eye go “ah, that’s just the identity dog”? I
thought so too. We might have even realized we didn’t need a dog
at all.

We also explicitly type our programs here and there because the
type-inference mechanism tries to be as accommodating as possible.
This is great. However, it also means that the inferred types will
often be way more general than we want them to be. For example,
consider the type Haskell infers for the expression 3 id.

> :t 3 id
3 id :: Num ((a -> a) -> t) => t

Here, Haskell sees that we are trying to apply the number 3 to the
function id, and infers the type of this expression according to that.
A fair logical deduction, considering 3 is a polymorphic number that
can be converted to a value of any type for which there is a Num
instance. Sure, 3 could be a function, why not? So, since we are
trying to apply this function 3 to yet another function of type a → a,
id, in order to obtain a value of value some arbitrary type t, Haskell
demands that there be a Num instance for (a → a) → t. Silly, I know,
yet a perfectly logical idea as far as the type-system is concerned,
which is why we, cognizant of a more sensible goal, should nudge
the type-inference mechanism in a sane direction by constraining
some of these wild thoughts.

We collaborate with type-inference, that’s what we do. The more


meaning we convey through types, the more we’ll be rewarded. For
example, if we actually expect 3 id to have type Bool, we can ask for
it explicitly.

> :t 3 id :: Bool
<interactive>:1:1: error:
• No instance for (Num ((a -> a) -> Bool))
arising from the literal ‘3’
(maybe you haven't applied a function
to enough arguments?)
• In the expression: 3
In the expression: 3 id :: Bool

This time, rather than Haskell inferring a silly type for our
expression, we get an error from the type-checker saying that the Num
instance our previous example was expecting could not be found.
This makes sense, why would there be a Num instance for (a → a) →
Bool that could be represented with the number 3? If we ever find
ourselves writing 3 id, chances are we wrote this by accident.
Maybe we “haven’t applied a function to enough arguments”, as
the error message kindly suggests.
Alternatively, if we know 3 is supposed to be an Integer number,
say, we can give 3 itself an explicit type, which will lead us to an
even better type error.

> :t (3 :: Integer) id
<interactive>:1:1: error:
• Couldn't match expected type ‘(a -> a) -> t’
with actual type ‘Integer’
• The function ‘3 :: Integer’ is applied to one
argument, but its type ‘Integer’ has none
In the expression: (3 :: Integer) id

Quite straightforward. According to its usage, 3 was expected to be


an expression of type (a → a) → t, yet it is an Integer, so naturally
the type-checker complains and we get to be thankful for that. The
more we tell Haskell about our types, the better the error messages
we get in return.

And, while here we are seeing this in the context of GHCi, we


should know that all of this applies to source code written in files
too. We will get similar error messages from the type-checker as
soon as we try to compile our source code, which will make the
compilation process fail, preventing sillily typed programs,
symptoms of misunderstanding, from existing at all.

But not only can Haskell tell us about the types of the expressions
that we have, it can also tell us about the types and the expressions
that we don’t. It sounds silly, I know, and you are right to be
skeptical. Nevertheless, skepticism doesn’t make this any less true.
Let’s see how.
112. Foldable
The and function we’ve been talking about so much is not really
called and but (&&). But beside its different name and fixity,
everything about (&&) is as we learned for and. We remain uncertain
as to the origin of this fascination with infix operators, but we’ll
play along and go with it. Mostly, and fits nicer in prose, that’s why
we’ve been using this fake name instead. Well, actually, it is not so
fake. There is in Haskell a function called and closely related to (&&),
but it has a different type, as reported by :type in GHCi.

and :: Foldable t => t Bool -> Bool

Herein lies our quest. We’ll implement and using not much beyond
GHCi. Well, first we need to understand what and is supposed to
do, and as and is not a fully parametrically polymorphic function,
we’ll have to rely on human documentation for this. The
documentation says that “and returns the conjunction of a
container of Bools. For the result to be True, the container must be
finite. False, however, results from a False value finitely far from
the left end”. Alright, that’s our goal. Let’s implement and.

First, “and returns the conjunction of a container of Bools”. This


suggests that we may have the opportunity to use (&&) to conjoin
the Bools in this container somehow. If we try to relate these words
to the type of and, Foldable t ⇒ t Bool → Bool, we can see how the
conjunction is indeed being returned as that standalone Bool, and
that presumably this t Bool thing is the “container of Bools” the
documentation talks about. There is a Foldable constraint on that f,
too. I suppose we’ll have to learn something about it too.

We know how to conjoin two Bools a and b as a && b. But a


containerful of them? How do we conjoin that? Well, maybe first
we should ask ourselves what a “container” is and how many Bools
are in there? If it’s just two, then it’s quite obvious that we should
treat them as a and b above. But what if there are more? Or, more
importantly, what if there are less than two Bools? How do we
conjoin that? Oh my. Before even attempting this, what if we take a
look at that Foldable constraint on f? Maybe there we’ll find more
information about how many Bools we are dealing with. Let’s ask
GHCi about Foldable, using the unsurprising :info command. Or,
if you feel like it, by looking at the surely beautifully arranged
documentation for this typeclass somewhere else.

> :info Foldable


class Foldable (t :: Type -> Type) where
{-# MINIMAL foldMap | foldr #-}
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
… and many more methods not shown here …

According to :info, the Foldable typeclass has approximately twenty


methods. Yes. However, we will ignore most of them because, as
indicated by the MINIMAL pragma, only two of them are actually
fundamental enough that must be explicitly defined, so we’ll focus
our attention on them. The rest of the methods are defined in
terms of these two. Well, actually, explicitly defining just one of
them is enough, according to the pragma, which suggests that these
two can be implemented in terms of each other like (==) and (/==)
could. This is important. Life is short, we have limited time and
capacity, and we can’t go paying attention to every little thingy that
comes before us unless we must, need or want to. We learn how to
identify what can be ignored, and ignore it for as long as we can or
want.
Of these two methods foldr and foldMap, let’s to look at the familiar
foldr. We recognize the name, it’s the right fold.

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

The main thing to notice is that the type of this foldr is a bit
different to the type we saw before. It talks about folding a t a,
where that t is a Foldable type-constructor, whereas before we
always talked about folding [a], a list of as.

foldr :: (a -> b -> b) -> b -> [a] -> b

Well, it turns out that lists are Foldable too. I mean, we already
knew that, of course, but moreover, if we look again at GHCi’s
output from before regarding :info Foldable, we can see some of
the existing Foldable instances listed as well. Among them, there’s
one for lists.

instance Foldable []

We haven’t really specified any instances for lists using the weird
Haskell list syntax before, so this might look a bit strange. So far,
we’ve only done this for the List we defined ourselves, the one with
the Nil and Cons constructors, but never for the one made out of
sweet [] and (:). The main thing to keep in mind is that at the type
level [] x and [x] mean exactly the same. In other words, much like
List or Maybe, [] is a type constructor of kind Type → Type which can
be applied to another type a by saying [] a in prefix form as every
other type-constructor, but it can also be applied to a as [a], using
some questionable syntax sugar. So, when the type of foldr takes []
to be its t, we end up with this:
foldr :: (a -> b -> b) -> b -> [] a -> b

Which is exactly the same as the type of foldr we’ve been seeing all
alone, but without some of its sugar:

foldr :: (a -> b -> b) -> b -> [a] -> b

So, what does this mean for the “conjunction of a container of


Bools”? Well, among other things, seeing how lists could be one of
these Foldable “containers”, it means that there could be zero, one,
two, many or infinitely many Bools in our t, and and should be able
to deal with all of that. We’ll need to figure out how to conjoin a
number of Bools other than two, then. Quite likely we’ll be using
foldr for that, considering how that’s the main vocabulary that
Foldable gives us.

Foldable is a typeclass for “things that can be folded”, and as almost


every other typeclass that ends with “able”, it’s a bit clunky. Also,
like Functor, it is limited to working with type constructors of kind
Type → Type, which restricts Foldable to list-like types containing
values of just one type, excluding things like Either or Pair. Well,
actually, just like in the Functor case, there are instances for Either
and Pair as partially applied type constructors of kind Type → Type,
allowing us to fold only their right hand side payload. And as
expected, we see a Foldable instance for Maybe too, the one-element
list.

instance Foldable Maybe


instance Foldable (Either x)
instance Foldable ((,) x)
Oh, right, Haskell uses the weird tuple syntax (a, b) rather than
Pair a b, so we need to worry about that. You see why we don’t like
these ad-hoc syntaxes? Anyway, much like [a] and [] a mean the
same, (a, b) means exactly the same as (,) a b. They are “just” two
different syntaxes for saying the same thing. Now, the interesting
thing about using (,) as a prefix type-constructor is that we get to
partially apply it if necessary. That is, we can use (,) x, say, to
obtain a type constructor of kind Type → Type where the leftmost
element of the tuple type constructed with this type constructor
will always have type x. This is what we see above in the Foldable
instance for (,) x. Actually, let’s implement that instance here
ourselves, so that we get a bit more comfortable with this awkward
syntax and the behaviour of foldr for tuples.

instance Foldable ((,) x) where


foldr f z (_, y) = f y z

As expected, foldr takes a binary operation f and an initial


accumulator z, and then uses f to combine the rightmost element
inside the tuple, y, with the initial accumulator z. That’s all. The
leftmost element of this tuple will of course be ignored, just like
fmap ignored it too. Oh, right, we never saw the Functor
implementation for (,) x. Well, for completeness, here it is:

instance Functor ((,) x) where


fmap f (x, y) = (x, f y)

See? The x stays unchanged, ignored, just like in the Foldable


instance for this container. And by the way, when we say
“container” this time, in Foldable, we really mean container and not
“just” a covariant type constructor as in the case of Functor. What is
a container? Ah, wouldn’t we all like to know. According to
Foldable, if we stare very hard at its documentation, it is anything
that could be converted to a list. This becomes evident when we see
foldr's documentation saying that the following equality must hold
for all Foldable instances:

foldr f z x = foldr f z (toList x)

That is, right folding some container x of type Foldable t ⇒ t a,


must give the same result as first converting that t a to [a] using
toList :: Foldable t ⇒ t a → [a] and then right folding that list. So,
yes, you should be uncomfortable and unsatisfied with Foldable,
that’s the sane reaction.

Anyway, let’s leave the questionable Foldable aside for a moment


and go back to and.
113. Politics
The documentation for and also says that “for the result to be True,
the container must be finite”. Alright, this makes sense. If we recall,
we said that conjoining Bools results in True only as long as the Bools
we conjoin are themselves True, which implies that we must be able
to inspect each and every Bool in our container to make sure they
are all True, which makes it impossible for us to work with infinite
containers. Or, does it? Tell me, is it true that all of the Bools in this
infinite container are True?

politics :: [Bool]
politics = False : politics

Our politics is infinite, yet without any doubt we won’t find any
truth in it. Of course, Haskell doesn’t know this at runtime, but as
it starts inspecting politics it will encounter a False value right
away, enough evidence to confirm that no, it is not true that all of
the Bools in this container are True. Thus, without further
exploration, we can confidently announce that the conjunction of
these booleans is False, even if this is an infinite container. Of
course, none of this should come as a surprise, considering the
documentation already talked about it when it said “False,
however, results from a False value finitely far from the left end”.
114. A hole new world
We have (&&), a function of type Bool → Bool → Bool, and we want to
create and, a function of type Foldable t ⇒ t Bool → Bool. Ideally, as
long as we are dreaming, we would like to find a function that
simply takes (&&) as input and gives us and as output. We can use
Haskell’s hole mechanism to search for this function if it exists, or at
least to discover some hints that could help us implement it
ourselves if necessary. Of course, we could also come up with an
implementation for this function by using our brains, as cavemen
did, but let’s be smart and use that brainpower to learn a new tool
instead, so that in the future we can avoid thinking about these
utterly boring matters. This will be our adventure.

> _foo (&&) :: Foldable t => t Bool -> Bool

_foo here is the function we are trying to find. It takes (&&) as its sole
input parameter and becomes an expression of type Foldable t ⇒ t
Bool → Bool as requested. The underscore at the beginning of the
name _foo tells Haskell that it should treat _foo as a hole, rather than
complain that something called foo is not defined, as it would
without the underscore. A hole? Let’s take a look at the output
from GHCi to appreciate a bit more what this means.

<interactive>:61:1: error:
• Found hole: _foo :: (Bool -> Bool -> Bool) -> t Bool ->
Bool

When we leave a hole in our expressions, like _foo, the type-checker


reports this as it would any other type error. However, it gives some
helpful information too. On the first line, the error message reports
that the type-checker found a hole named _foo of type (Bool → Bool
→ Bool) → t Bool → Bool. This is perfect, we know we expect our
idealized _foo to be a function that takes (&&) as input and returns
an expression with and's type as output, and this is exactly what we
see here. Then, the message says something about t.

‘t’ is a rigid type variable bound by


an expression type signature:
forall (t :: Type -> Type).
Foldable t => t Bool -> Bool

A rigid type variable. This means that while many concrete things
could take the place of this t, it is known that the t must satisfy
some expectations, it can’t be just any t. In our case, we are
demanding that t be an instance of Foldable of kind Type → Type.
These expectations about t were conveyed, bound by, the explicit
type signature we gave to the whole _foo (&&) expression, but of
course, it could have been different. For example, consider this
other example.

> _x + 3
<interactive>:61:1: error:
• Found hole: _x :: a
Where: ‘a’ is a rigid type variable bound by
the inferred type of ‘it’ :: Num a => a

Here our hole is one of the inputs to (+). This time we are not
explicitly giving a type to anything, yet Haskell knows that a, the
type of our hole _x, is a not just any type variable, but a rigid one
expected to be an instance of Num as required by the type of (+),
which also says that its inputs and output must have the same type.
Haskell inferred this precise knowledge about a which the rest of
the type system can now use, including the hole mechanism. And
that it thing that’s mentioned there? In GHCi, it is a magical name
given to the expression the REPL is currently dealing with, so in
our case it is _x + 3, meaning that it, according to (+), has the same
type as 3, and from this Haskell infers the type of _x. What we are
seeing here, essentially, is type inference at work, determining what
the type _x should be even when we haven’t come up with an
expression to take its place yet.

Things are a bit different if we let type inference run wild by, say,
not constraining the hole at all.

> const True _maize


<interactive>:70:12: error:
• Found hole: _maize :: b
Where: ‘b’ is an ambiguous type variable

In this example, nothing in the type of const :: a → b → a nor in the


expression that we wrote, const True _maize, constrains what our
polymorphic _maize should be. So the type-checker tells us that b,
rather than being a rigid type variable, is an ambiguous one, which
is Haskell’s way of saying that _maize could be anything.
115. Adventure
Back to _foo (&&). We see that in the feedback we got from the type-
checker we also got a list of possible valid substitutions for _foo.
This list mentions expressions whose types satisfy all of the
expectations the type-checker has identified for this hole.
Semantically, these expressions might do the wrong thing. But
really, what does it mean to be wrong? We can barely tell that
ourselves. At least these expressions type-check, so they are a good
starting point for further exploration. Among them, we find two
that immediately catch our attention.

Valid substitutions include


foldl1
:: forall (t :: Type -> Type) (a :: Type)
. Foldable t
=> (a -> a -> a) -> t a -> a
foldr1
:: forall (t :: Type -> Type) (a :: Type)
. Foldable t
=> (a -> a -> a) -> t a -> a

We don’t really know what these do, but their names foldl1 and
foldr1 suggest a relationship with left folding and right folding.
And since we know that only right folding works with infinite lists,
which we’ll most likely need, as discussed before, we’ll focus our
attention on foldr1. Although we are a bit hesitant, because
somewhere in and's documentation we see something about values
“finitely far from the left end”, which suggests maybe a left fold is
better. Hmm, let’s try with foldr1 first.
foldr1 :: Foldable t => (a -> a -> a) -> t a -> a

In our case, the as would be Bools, as mandated by the type of (&&):

foldr1 (&&) :: Foldable t => t Bool -> Bool

Excellent. So, we have something with the same type as and. Let’s
try it and see what happens.

> foldr1 (&&) [True, True]


True

Hmm, that actually worked. Well, perhaps we were just lucky,


seeing how True represents 50% of the possible outcomes of this
function. Let’s try all the other combinations of True and False
pairs.

> foldr1 (&&) [True, False]


False
> foldr1 (&&) [False, True]
False
> foldr1 (&&) [False, False]
False

Incredible, this works as expected. What about conjoining some


longer lists? For example, we expect a False result when conjoining
containers with at least one False element in them.
> foldr1 (&&) [False, False, True, False]
False
> foldr1 (&&) [True, True, False, True, False]
False
> foldr1 (&&) politics
False

Fascinating. It even deals with the infinite politics. And,


supposedly, this should work for containers with just one element
in them too, one False. The documentation doesn’t say so
explicitly, but it also doesn’t not say it when it mentions that “False,
however, results from a False value finitely far from the left end”. It
should work.

> foldr1 (&&) [False]


False

Indeed, False. So far we are complying with and's expectations. True


is a bit trickier, it’s true. We know foldr1 (&&) works fine with two
True elements, and according to what the documentation for and
didn’t not say, it should work for finite containers of any length,
insofar as they are finite and don’t contain any False elements.

> foldr1 (&&) [True, True, True, True]


True

Right, it works. And presumably, it should work with containers


with just one True element in them too. It’s unclear to us how
conjoining just one boolean works, considering the conjunction of
booleans is a binary operation, meaning that it takes two booleans
as input, but we’ll just play along for now and dive deeper into this
afterwards. After all, this is supposed to be an adventure.

> foldr1 (&&) (False, True)


True

What? Well, yes, this is fine. Remember that through the eyes of
Foldable, the expression (False, True) is a container of just one
element, True, just like [True] is.

> foldr1 (&&) [True]


True

And finally, as advertised, using foldr1 (&&) on an infinite list won’t


work. For example, foldr1 (&&) (repeat True) runs and runs and
runs, never returning any value, for repeat True is an infinite list
with just True elements in it.

repeat :: a -> [a]


repeat a = a : repeat a

We can’t really display the infinite loop here, though. What would
that even look like?
116. Rebelión
Are we done? Have we successfully impletemented and? Well,
foldr1 (&&) certainly delivered all the answers we wanted, but there
is something we neglected. Let’s take a look at the type of foldr1
(&&) again.

foldr1 (&&) :: Foldable t => t Bool -> Bool

Here, t Bool could be [Bool] or Maybe Bool, for example, meaning we


should be able to use [] or Nothing as inputs to this function too.
But what would be the result if we did that? Reading and's
documentation, we are inclined to think that it should be True, but,
as before, this is mostly because it isn’t clear that it should be False,
so we fall back to the alternative. Anyway, let’s try and see what
happens.

> foldr1 (&&) []


*** Exception: Prelude.foldr1: empty list

What? Exception? What is that? How is this possible? Are we not


getting a Bool as result, even if that’s what the type of foldr1 (&&) []
promises? What are we getting? We’d like our money back, please.

All the functions we have seen so far have been total functions,
meaning that they deal with all of their possible inputs by
returning a suitable value of their output type as expected. This
makes sense, why would functions do something other than this?
Yet, here we have foldr1, failing to deliver the Bool it promised.
foldr1 is what we call a mistake, also known as a partial function,
meaning it is not total, meaning it diverges for some of its inputs.
We can easily conclude that foldr1 is a partial by analyzing its type.

foldr1 :: Foldable t => (a -> a -> a) -> t a -> a

Here, foldr1 is saying that it will produce an a as output. This


function has two ways of coming up with the a that it could
eventually return: It either uses the function with type a → a → a to
combine two values of type a which it must first obtain somehow,
or it can just take the a out of the given container t a and return
that. However, if the container given as input is empty, there would
be no a at all, so the function would be forced to diverge by using
undefined, infinitely looping, or aborting its execution with an
exceptional error message as the one we saw just now. Only these
absurd expressions would type-check. In other words, this function
is necessarily partial. And, considering there’s nothing good to be
said about partial functions, we can conclude that the type of this
function is wrong, and that foldr1 arguably shouldn’t exist. But
having foldr1 be partial was a conscious choice, not an accident. A
better choice would have been to return Maybe a, rather than a. That
way, the function could result in Nothing rather than diverging
when faced with an empty container.

foldr1 :: Foldable t => (a -> a -> a) -> t a -> Maybe a

It’s a good thing, though, that we caught this. We almost shipped a


partial and by accident. It could have been a catastrophe. As
responsible programmers we must uncover these things, we must
keep them from harming others. We find a structure, we tear it
down. We find a challenge, we take it. A system, we subvert it. A
boundary, we trespass it. Civilization relies on us, we can’t be
reckless and just trust. We don’t trust, ever. Only once we’ve tamed
these evils, only once we’ve challenged all authority, can we be at
ease. We prove our software is correct, that’s what we do.
117. Or something
We need something else. foldr1 won’t do. A quick look at the type
of foldl1 suggests that it will suffer from the same problem, so we
discard it as well. Let’s try with foldr instead. After all, the name
foldr1 suggests there’s some relationship with it, and we know from
before that foldr can deal with empty containers just fine.

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

We can see in this type that if the container t a is empty, foldr will
have to output the b that was provided as input. So, what should
this initial b be? When the container is empty, should foldr return
True or False? We hinted a while ago that True seemed to be a good
choice, but not for its own merit, but rather because False didn’t.
Can we do better? Can we justify our choice?

Well, foldr1 seemed to be doing just fine except in the case of


empty containers, so we could try to understand what it was doing
and copy that. Or better yet, we could not, because quite frankly
this caveman approach to understanding how things behave
depending on which buttons we push is insufferable. Do you feel
the air getting thicker and the neurons dying? We need clarity, fresh
air, we need a monoid or something.

Hey, a monoid, that’s an interesting idea. We encountered one of


those back when we were just discovering folds. We remember
having used both its associative binary operation and identity
element as the arguments to foldr. Maybe we can do it here too?
We have the binary operation already, (&&). Is it associative? That is,
is a && (b && c) equal to (a && b) && c? Yes, yes it is. We can prove
that this is true using equational reasoning as we’ve done many
times before. However, we won’t do it here because it would be
boring. Instead, let’s look for an identity element for our monoid.
An element which the Monoid typeclass calls mempty, for which all of
a, mempty && a and a && mempty are equal.

False && False == False


False && True == False
True && False == False
True && True == True

It’s easy to see that this identity element can’t possibly be False,
because each time False appears as one of the operands to (&&), the
resulting conjunction becomes False too, even if the other operand
was True. On the other hand, True always preserves the truth value
of the other operand. It’s as if True wasn’t even there. In other
words, True is our identity element. We found it. Let’s write our
Monoid instance for the conjunction of Bools.

instance Monoid Bool where


mempty = True
mappend = (&&)

Alright, how do we implement and using this? In the past we relied


on mconcat when implementing sum and product, maybe we can use
mconcat here too.

mconcat :: Monoid a => [a] -> a

Hmm, not quite. mconcat expects a list as input, whereas and was
supposed to take a Foldable container.
and :: Foldable t => t Bool -> Bool

However, we did say that a Foldable container was one that could
be seen as a list. And, actually, we even talked about a function
toList of type Foldable t ⇒ t a → [a] that could convert the
container to a list. So maybe all we need to do is convert our
container to a list using toList before feeding it to mconcat. That is,
we should compose these two functions. Let’s ask GHCi to
confirm whether our idea makes sense.

> :t compose mconcat toList


compose mconcat toList :: (Foldable t, Monoid a) => t a -> a

Interesting. It doesn’t look quite like and's type, though. There is a


new Monoid a constraint there we were not expecting. And, by the
way, this is the first time we are seeing two constraints in a type.
Both of them need to be satisfied by our chosen t and a in order for
things to type-check. Where did these constraints come from? Well,
mconcat brought the Monoid a constraint, toList brought the Foldable
t one, and all compose did was preserve them. What else could it do?
But, if we recall, some minutes ago we created Monoid instance for
Bool, so we can pick Bool to be our a, immediately satisfying that
Monoid a constraint, thus making it disappear. We can ask GHCi to
type-check this for us by explicitly giving and's type to compose
mconcat toList.

> :t compose mconcat toList


:: Foldable t => t Bool -> Bool
compose mconcat toList :: Foldable t => t Bool -> Bool

Yes, Haskell is happy. At last, let’s call this and.


and :: Foldable t => t Bool -> Bool
and = compose mconcat toList

Does it work? Of course it does. We tamed this beast with a


monoid, why wouldn’t it?

> and [False, True]


False
> and (False, True)
True
> and [True, True]
True
> and [True]
True
> and Nothing
True
> and [False]
False
> and (True : repeat False)
False

We can see now how the conjunction of zero elements comes to be:
It is simply the identity element, True, that’s all. And similarly, the
conjunction of one element is simply that one element, which is
semantically the same as conjoining that element with True, the
identity element. Mystery solved.
118. Disjunction
Actually, giving a Monoid instance to Bool maybe isn’t such a great
idea. Perhaps there are other monoids for booleans beyond
conjunction, and by giving Bool itself a Monoid instance we are
somewhat implying that conjunction is the most important
monoid there is, or something along those lines. Indeed, we saw this
happen for Natural numbers too, where both the addition and
multiplication of Naturals were a monoid, so we opted to create two
distinct datatypes Sum and Product, and give monoid instances to
them instead. Maybe we should do that here too.

Is there really another monoid, though, or are we doing this in


vain? Yes, yes there is one. It is called disjunction, it is different from
conjunction, and it represents the idea of at least one of two
booleans being true. In Haskell, the disjunction function is called
(||), and it’s often read out loud as “or”.

(||) :: Bool -> Bool -> Bool


True || _ = True
False || x = x

We can immediately say two things about (||). First, as expected,


the evaluation of the second Bool does not happen until we have
confirmed that the first Bool is False. This makes sense as much as it
made sense for (&&) to avoid evaluating its second input parameter
unless truly necessary. Why continue working if we already have an
answer?

Second, we can see that the identity element for the disjunction of
booleans is False. We can tell this by observing that a True operand
forces the result to be True even if the other operand was False,
whereas a False operand lets the other operand state its truth.

Is disjunction an associative binary operation? Yes it is, you can use


equational reasoning to prove it.

So we have identified our second monoid, disjunction. Let’s give it


a name, a type, and a proper Monoid instance.

data Disjunction = Disjunction Bool

instance Monoid Disjunction where


mempty = Disjunction False
mappend (Disjunction a) (Disjunction b)
= Disjunction (a || b)

Actually, in Haskell we don’t call this Disjunction but Any,


conveying the idea that the result of this binary operation is True
whenever any of its inputs is True. Or, more likely, we probably use
the word “any” because it’s shorter than the word “disjunction”.

data Any = Any Bool

instance Monoid Any where


mempty = Any False
mappend (Any a) (Any b) = Any (a || b)

Similarly, the conjunction monoid is actually represented by a type


called All, conveying the idea that all of the inputs to this its
function must be True in order for the result to be True.
data All = All Bool

instance Monoid All where


mempty = All True
mappend (All a) (All b) = All (a && b)

And, of course, seeing as there’s no Monoid instance for Bool


anymore, we need to wrap our Bools in All and then unwrap them
in order to implement and, just like we did for sum a while ago.

and :: Foldable t => t Bool -> Bool


and x = case mconcat (fmap All (toList x)) of
All z -> z

Or, assuming a function called unAll of type All → Bool that could
be used to remove the All wrapper, we could make and's
implementation a bit cleaner, in a point-free style, as follows:

and :: Foldable t => t Bool -> Bool


and = compose unAll
(compose mconcat
(compose (fmap All) toList))

Oi, that’s not cleaner, is it?


119. Dot
Function composition is one of the most commonly used tools in
Haskell and functional programming, probably second only to
function application. As such, it gets to claim one of the most
beautiful and minimal infix operators: The dot.

(.) :: (b -> c) -> (a -> b) -> (a -> c)


(.) = compose

So far we’ve been talking about compose because it’s easier to use it in
prose, but in reality compose doesn’t even exist with that name out of
the box in Haskell. We use (.) instead.

and :: Foldable t => t Bool -> Bool


and = unAll . mconcat . fmap All . toList

Ah, much better. As it’s usual with function composition, we read


things from right to left. So first we apply toList to t Bool, which
results in a value of type [Bool] which we then transform to [All] by
using fmap All, which we then mconcat to a single All before finally
transforming it back to a Bool by means of unAll.

And, by the way, as we learned before, function composition is an


associative operation, meaning that a . (b . c) and (a . b) . c are
semantically the same, so we can just drop the parentheses
altogether and let Haskell associate these compositions however it
wants.
120. Disjunctivitis
The counterpart to and, the disjunction of a container of Bools,
unsurprisingly, is called or. And its implementation shouldn’t be
surprising either, considering all we’ve learned so far. Let’s just go
ahead and implement it. As before, we will be assuming the
existence of a function unAny of type Any → Bool that we can use to
remove the Any wrapper.

or :: Foldable t => t Bool -> Bool


or = unAny . foldMap Any

This time, for no particular reason, we use foldMap Any rather than
mconcat . fmap Any . toList as we did in our latest version of and. If
we recall, beside foldr, foldMap was the other function we could
have implemented when defining a Foldable instance instead of
foldr, so we figured maybe we could use it.

foldMap
:: (Foldable t, Monoid m) => (a -> m) -> t a -> m

Unsurprisingly, this works perfectly fine, because monoids.


> or [False, True]
True
> or (True, False)
False
> or [False, False]
False
> or [False]
False
> or Nothing
False
> or [True]
True
> or (False : repeat True)
True

We can even see the laziness of disjunction in action.

> or [True, undefined]


True

Monoids, right? Anyway, enough monoids for now. Let’s go


somewhere else.
121. Parsers
A long time ago we introduced the idea of parsers as functions
taking Strings as input and returning more specific values such as
Natural or Bool. Or, more generally, they take a type less precise than
their output as input. We also learned that these parsers may fail.
For example, trying to parse a Bool value out of the input String
"hello" doesn’t make much sense, so this parser could fail by
returning Nothing in that case. That’s the general idea. Let’s build
some parsers.

Our first parser will be one that parses a natural number out of our
string. That is, it will turn a String like "125" into the Natural
number 125. Failing, of course, to parse things like "chocolate".

naturalFromString :: String -> Maybe Natural

This function would look at the individual characters in the given


String from left to right, and as long as they are all digits, it will
combine them somehow into that Natural. We are lacking some
tools to implement this, though. For example, we will need to be
able to determine if an individual character is a digit or not.

isDigit :: Char -> Bool

In Haskell, we can use the Char datatype to talk about the individual
characters in a String. For example, “a”, “b” and “c” are the
individual characters in the string “abc”, and just like how we can
use the syntax "abc" to talk about this string literally, we can use 'a',
'b' and 'c' to talk about the individual characters, using this special
single quotes ' syntax. We can ask GHCi to confirm this.
> :t 'a'
'a' :: Char
> :t '7'
'7' :: Char
> :t 'ж'
'ж' :: Char

Indeed, these are all values of type Char. So, presumably, we want
isDigit to check whether the given Char is one of the digits between
'0' and '9'.

isDigit :: Char -> Bool


isDigit '0' = True
isDigit '1' = True
isDigit '2' = True
isDigit '3' = True
isDigit '4' = True
isDigit '5' = True
isDigit '6' = True
isDigit '7' = True
isDigit '8' = True
isDigit '9' = True
isDigit _ = False

Quite straightforward, even if a bit long. So, if isDigit succeeds, we


know we can extract a numeric value from this digital Char. How?
Well, we could simply convert this digit to its Natural
representation.
digitFromChar :: Char -> Natural
digitFromChar '0' = 0
digitFromChar '1' = 1
digitFromChar '2' = 2
digitFromChar '3' = 3
digitFromChar '4' = 4
digitFromChar '5' = 5
digitFromChar '6' = 6
digitFromChar '7' = 7
digitFromChar '8' = 8
digitFromChar '9' = 9

Is this good? Well, no. It does work for the Chars that happen to be
digits as told by isDigit, sure, but it completely falls apart for every
other Char like 'r' or '?'. digitFromChar is a partial function, and
that makes it bad. Luckily, Haskell will let us know that our
patterns are insufficient, that they don’t handle all possible Char
inputs, nudging us in the right direction so that we fix this. Now,
we only plan to use this function internally within
naturalFromString after isDigit confirms that we are indeed dealing
with a digit, so we might argue that this is acceptable. However, if
that was the case, why would we be exposing digitFromChar for
everybody else to use at all, giving it such a prominent name? No,
no, no, this is unacceptable. We need to make digitFromChar a total
function, we need it to return something even when there’s nothing
to return. Nothing to return.
digitFromChar :: Char -> Maybe Natural
digitFromChar '0' = Just 0
digitFromChar '1' = Just 1
digitFromChar '2' = Just 2
digitFromChar '3' = Just 3
digitFromChar '4' = Just 4
digitFromChar '5' = Just 5
digitFromChar '6' = Just 6
digitFromChar '7' = Just 7
digitFromChar '8' = Just 8
digitFromChar '9' = Just 9
digitFromChar _ = Nothing

Ah, yes, much better. We can simply wrap the resulting Natural in a
Maybe and return Nothing when the given Char is not a digit. And
what is digitFromChar now if not another parser? It takes a Char, a
“less precise” data type from the point of view of what it means to
be a digit, and converts it into a Natural number if possible. And
with this, we don’t even need isDigit anymore, seeing how
digitFromChar can already deal with Chars that do not represent
digits.
122. Wild bool
We find a Bool in the wild. What does it mean? Hard to tell, isn’t it?
A boolean says “true” or “false”, but that’s all it ever does. Without
knowing what the fact the bool was talking about in the first place,
we can’t really assign a meaning to it. We must do better than wild
bools.

isDigit :: Char -> Bool

digitFromChar :: Char -> Maybe Natural

Both isDigit and digitFromChar, ultimately, answer the question of


whether there is a digit in that Char. However, whereas we can only
interpret the Bool's intentions as long as we remain aware of its
relationship with the original Char, the Maybe Natural we obtain
from digitFromChar has a meaning by itself even after the
relationship with the original Char is lost, accidentally or not. In
Maybe Natural, or rather, in the Natural within, if any, there is proof
that a Natural came to be somehow. Granted, Natural numbers can
be created out of thin air, so perhaps this example is not the most
self-evident. However, imagine the Natural number being a secret
password, or the phone number of the love of our life. Would we
rather have True or the actual number in our hands? I thought so
too.

We call this problem boolean blindness, and we’d like to avoid it. So,
instead of booleans, we prefer to use sum types able to carry a proof
of some fact, like Maybe. To understand how, let’s take a look at
filter, a traditional function not exactly worth perpetuating.
filter :: (a -> Bool) -> [a] -> [a]

This function takes a list of as and returns a new one where some of
the original elements have been excluded according to a decision
made by the function a → Bool. However, we can’t really tell by just
looking at filter's type whether a value is excluded when the
function returns True or when it returns False. And the function’s
name “filter” doesn’t help either. So let’s grow up, disregard this
misleading tradition and try something else instead.

filter :: (a -> Keep) -> [a] -> [a]

data Keep = Keep | Skip

“Mr. President, sir, this is what we were looking for. We embrace a


different name and suddenly, without any further work, the
purpose of the function that decides whether to keep or skip an
element becomes perfectly clear. We just rebrand it, Mr. President.
And moreover, Keep and Skip rhyme, so they could jingle your next
campaign. We couldn’t possibly do better, Mr. President, sir. We’ll
announce it with fanfare, people will be thankful.”

Yet, back in the wild, many months, bureaucrats and happycoins


later, we the people find a Keep and still can’t tell what it means.
Keep what? And do we keep it in the resulting list or do we keep it
from being listed? You see, once again we are at the mercy of
naming choices and whether we remember how this Keep came to
be. We won’t be keeping this filter, no, that’s for sure.

filter :: (a -> Maybe b) -> [a] -> [b]


This is better. Not only have we stopped suffering from boolean
blindness and naming choices, but also we have added some
parametric polymorphism, and that is good. This filter takes a list
of as and returns a list of bs, and thanks to the enlightenment
brought to us by parametricity, we can confidently say that any
such b must be an a that was successfully transformed by the
function a → Maybe b. Of course, nothing prevents filter from
having a silly implementation that, say, always returns an empty
list, but as we said before, at some point we are responsible for
telling the computer what to do at least once, and this is where.
Nonetheless, as usual in these situations, we can clarify filter's
intentions by involving an identity, and saying that filter Just
behaves like the identity function for lists.

> filter Just []


[]
> filter Just [7]
[7]
> filter Just [2, 3]
[2, 3]

Alternatively, we could take a step back, a deep breath, and realize


that the foldMap method of the Foldable typeclass we saw before,
together with its laws, already gave us a dependable, and even more
powerful way of filtering lists and other containers by means of
monoids. We don’t need filter at all.

foldMap
:: (Foldable t, Monoid m) => (a -> m) -> t a -> m

How? Well, if we pick m to be [b], it’s easy to see how we could


implement filter on top of this more general foldMap.

filter :: (a -> Maybe b) -> [a] -> [b]


filter f = foldMap (\a ->
case f a of
Just b -> [b]
Nothing -> mempty)

Run from the boolean, run to the monoid.

Anyway, for completeness, know that the original filter that cared
for Bools discards every element for which the function a → Bool,
which we call the predicate, returns False. That’s what the filter
function we’ll often encounter in Haskell does.
123. Surjection
Anyway, even if digitFromChar doesn’t encourage boolean
blindness, there is still a small issue with it. Or perhaps an infinitely
large one, depending on how we look at it. We know that a value of
type Natural can represent any natural number, including the ones
from 0 to 9 we are interested in. However, it can also represent
values outside this range. So, while in digitFromChar we acquired
some very precise knowledge about a Char being a single digit
number, we lost that knowledge as soon as we picked Natural as the
type we use to represent the concept of a digit. And as soon as we
lose this knowledge, we can’t rely on the type-system to guarantee
that the Natural in question is a single digit anymore. Not unless we
remember the relationship between this Natural and the original
Char.

There is a name for this phenomenon coming from Set Theory, a


boring branch of mathematics. We say that digitFromChar is not a
surjective function, which means that the image of digitFromChar is
not the same as its codomain. Through the eyes of Set Theory, the
type of digitFromChar, Char → Maybe Natural, says that this function
converts an element from the set of all Chars, its domain, into an
element from the set of all Maybe Naturals, its codomain. However,
while digitFromChar can take any Char as input, it only ever returns a
handful of elements from its codomain as output. Namely, Nothing
and Just the numbers from 0 to 9. We call the subset of the
codomain, comprising only the values that the fuction could
actually return, its image. And when the image and the codomain
of a function are equal, we say a function is surjective. Thus,
digitFromChar is not a surjective function, for its image and
codomain are different.
So why is this important? Why do functions need to be surjective?
Well, they don’t. We just took the opportunity to explain this
property, that’s all. We now add this new vocabulary to our latent
knowledge, we enrich our cognitive pattern recognition skills with
it, and we move on.

However, in our case, it turns out that we’ll end up with a


surjective digitFromChar by accident, as a consequence of chasing
our goal of not losing knowledge about the fact that our possible
Naturals have just one digit. In other words, the cardinality of
Natural is too big. We only have ten distinct digits we may
successfully parse, yet Natural suggests something else. We need a
datatype with a cardinality of ten.

data Digit = D0 | D1 | D2 | D3 | Dog


| D5 | D6 | D7 | D8 | D9

This new datatype, Digit, has exactly ten distinct constructors


which we can use to convey the ten distinct digits of a decimal
number system. The names of these constructors are irrelevant, as
highlighted by Dog, but we will use them according to their
Western-Arabic expectations. In case you are wondering, a dog
often has four legs. That’s our mnemonic.
digitFromChar :: Char -> Maybe Digit
digitFromChar '0' = Just D0
digitFromChar '1' = Just D1
digitFromChar '2' = Just D2
digitFromChar '3' = Just D3
digitFromChar '4' = Just Dog
digitFromChar '5' = Just D5
digitFromChar '6' = Just D6
digitFromChar '7' = Just D7
digitFromChar '8' = Just D8
digitFromChar '9' = Just D9
digitFromChar _ = Nothing

Much better. Now, not only is the returned Digit a proof that we
were able to obtain what we desired out of this Char, but it is also a
proof that what we obtained is one among ten possibilites, not
more.

And, as promised, we accidentally made digitFromChar a surjective


function, seeing how its image is now equal to its codomain Maybe
Digit. We don’t really care about this, though. This is mostly a
curiosity for us. For example, we could imagine a digitFromChar with
type Char → Either String Digit that returns a Digit whenever
possible, or a String saying "Not a digit" otherwise. This function
would not be surjective anymore, for its codomain would be bigger
than its image, but it would still perfectly address our decimal
concerns.

For practical arithmetic purposes, at some point we will likely want


to convert this Digit to a Natural number. Coming up with a
function of type Digit → Natural that accomplishes this should be
quite straightforward.
fromDigit :: Digit -> Natural

And of course, once we can convert one Digit into a Natural


number, we’ll want to convert a list of them into an even bigger
Natural number.

fromDigits :: [Digit] -> Natural


fromDigits = foldl' (\z a -> z * 10 + fromDigit a) 0

This function works just fine, as witnessed by our fascination as we


play with it in the REPL.

> fromDigits [D1]


1
> fromDigits [D1, D2, D3]
123
> fromDigits [D0]
0
> fromDigits [D0, D0]
0
> fromDigits [D0, D2]
2
> fromDigits [D3, D0, D0]
300
> fromDigits [Dog, D0, Dog]
404
> fromDigits []
0

Whether returning 0 in the case of the empty list makes sense or not
is an interesting conversation starter. It probably does, though,
considering how sum did it, and how fromDigits and sum are similar.
You see? We are already having a conversation. Like bringing up
the weather, it always works.
124. Type synonyms
We know how to turn a Char into a Digit, if possible, and we know
how to turn many of them into a Natural. We have most of the
pieces we need to implement naturalFromString, except the one that
will take a String and convert it to a list of Chars.

charsFromString :: String -> [Char]


charsFromString = id

Huh. What? Yes, it turns out that a String is just a list of Chars.

type String = [Char]

String is what we call a type synomym, merely a different name for


the type [Char]. Type synonyms can be convenient if the original
type is a bit too cumbersome to write. That’s pretty much it. It’s a
bit hard to justify this particular type synonym on these grounds,
but here it is, so we’ll use it. Any time we mention String in our
types, the type-checker will actually interpret it as [Char].
Everything we can do with a [Char] we can do with a String too,
since they are exactly the same type. Which, among other things,
means that we can use Haskell’s traditional list syntax for building
them.

> "abc" == ['a', 'b', 'c']


True
> ['a', 'b', 'c']
"abc"
> take 2 ('a' : 'b' : 'c' : [])
"ab"
The fact that we can write "abc" rather than the noisier ['a', 'b',
'c'] or ('a' : 'b' : 'c' : []) is just syntactic sugar. These three
expressions are all the same.

From a didactic point of view, Strings being a plain old list is quite
handy. We get to reuse all the knowledge we have about lists, such
as the fact that we can pattern match on them:

> case "abc" of { x : y : _ -> (x, y) }


('a', 'b')

Or, that their concatenation is a monoid:

> mempty :: String


""
> mappend "ab" "cd"
"abcd"

By the way, unrelated, rather than writing mappend, we can write


(<>), the infix version of this function. It’s exactly the same, it
works for any monoid, but it can look a bit nicer when used
multiple times:

> "ab" <> "cd" <> mempty <> "ef"


"abcdef"
> import Data.Monoid
> Sum 1 <> Sum 2 <> Sum 3
Sum 6

We now know how to obtain a list of Chars from a String. We are


closer to implementing naturalFromString.
125. Sequence
These are the interesting functions we have defined so far:

digitFromChar :: Char -> Maybe Digit

fromDigit :: Digit -> Natural

fromDigits :: [Digits] -> Natural

And we know that our String is a list of Chars. So how do we


implement naturalFromString, then?

naturalFromString :: String -> Maybe Natural

If we fmap digitFromChar over that String, we end up with a value of


type [Maybe Digit] where each Nothing in that list represents a non-
digit Char in the original String. That’s not really what we want, we
need a value of type [Digit] that we can use with fromDigits.
Nonetheless, it’s perfectly reasonable to find ourselves
encountering these Maybes as part of our input, seeing how we only
consider some Chars as acceptable for our purpose, and, ideally, we
want to identify and mark the undesirable ones as soon as possible
so that we can prevent any further work on them. That we can’t use
fromDigits, that our program fails to compile if we try to do so, is a
relief.

How do we proceed, then? Well, we could simply discard all of the


Nothing values in a list of Maybes, and only keep the Just payloads, if
any.
catMaybes :: [Maybe a] -> [a]

This function, with its name being a proof of how hard it is to


name things, comes out of the box with Haskell and does what we
want. However, we want the wrong thing. For example, think
about what the result of catMaybes (fmap digitFromChar "1p3")
would be. fmap digitFromChar will map some Chars to Digits and
some Chars to Nothing, preserving the order in which they appear in
the original String, [Just D1, Nothing, Just D3]. But then, catMaybes
will simply discard that Nothing, remove the Just wrapping, and give
us back [D1, D3], a value which we would be able to successfully
convert to the Natural number 13 afterwards, even if the original
String "1p3" certainly didn’t mean that. No, no, catMaybes type-
checks, but it is not what we want at this time. It would be perfect if
we wanted to “find all the digits in a string”, though.

A second alternative is to simply refuse to provide any result unless


all of the Chars in our String are digits.

sequence :: [Maybe a] -> Maybe [a]

If we dare ask GHCi about it, we’ll find that the type of this aptly
named function, sequence, is much more general. But for now, we’ll
just say sequence works with lists and Maybes as we see here. The
name sequence won’t make sense for the time being either, but we’ll
see later on that it is perfect.
> sequence []
Just []
> sequence [Nothing]
Nothing
> sequence [Just 1]
Just [1]
> sequence [Just 1, Nothing, Just 2]
Nothing
> sequence [Just 1, Just 2]
Just [1, 2]
> sequence [Just 1, Just 2, Nothing]
Nothing

In other words, sequence causes the whole output to be Nothing if


there is at least one Nothing within the original list. Otherwise, it
gives us Just a list with the payloads of the individual Just
constructors from the input list. Much like and and its conjunction
of Bools, except here we have Nothing instead of False, and Just
something instead of True.

The implementation of sequence is quite straightforward:

sequence :: [Maybe a] -> Maybe [a]


sequence [] = Just []
sequence (Nothing : _) = Nothing
sequence (Just a : ays) =
case sequence ays of
Nothing -> Nothing
Just as -> Just (a : as)

And with this, we can finally implement naturalFromString parser


by simply composing some of our functions.
naturalFromString :: String -> Maybe Natural
naturalFromString =
fmap fromDigits . sequence . fmap digitFromChar

This is what programming is about, really. Finding how, what and


when to compose. The implementation of naturalFromString, which
we read from right to left, says that first we will apply digitFromChar
to each of the Chars in the given String, which results in a value of
type [Maybe Digit] which we then convert to a Maybe [Digit] by
means of sequence. And finally, if the Maybe [Digit] in question is
Nothing, it means we can’t possibly convert the given String to a
Natural number, so we just return Nothing. But if sequence resulted
in Just, then we apply fromDigits to its payload and that’s our final
result. But rather than manually dealing with whether sequence
results in Just or Nothing, we rely on the functorial capabilities of
Maybe, which allow us to simply fmap fromDigits over it and rest
assured that our result will be correct.

> naturalFromString "1"


Just 1
> naturalFromString "12"
Just 12
> naturalFromString "ab"
Nothing
> naturalFromString "34r"
Nothing
> naturalFromString "0"
Just 0

Excellent. Well, almost. Look at this.


> naturalFromString ""
Just 0

See? I told you that whether fromDigits returned 0 or not in case of


an empty list was an interesting converstation piece, and here we see
a consequence of our choice. We stand by our choice of fromDigits
returning 0 when given an empty list of Digits as input. However,
that something makes sense there, at that particular level of
abstraction where we concern ourselves with Digits, doesn’t imply
that it makes sense here, where we concern ourselves with Strings.
Different perspectives often imply different concerns. This time we
would like naturalFromString to fail by returning Nothing if the given
String is empty, because it doesn’t make sense to successfully parse a
number out of an empty string. Alright, this is easy enough to fix.
We can exclude it from further processing by pattern matching on
the input String and returning Nothing right away when it is "".

naturalFromString :: String -> Maybe Natural


naturalFromString = \s ->
case s of
"" -> Nothing
_ -> fmap fromDigits
(sequence (fmap digitFromChar s))

Finally. naturalFromString does exactly what we wanted.


126. Split
We know how to parse a Natural number from a String now, great.
But what if we want to parse two of them from the same String, say,
separated by a comma ,?

> :t twoNaturalsFromString
twoNaturalsFromString
:: String -> Maybe (Natural, Natural)

> twoNaturalsFromString "123,45"


Just (123, 45)

We could implement twoNaturalsFromString from scratch, but we


won’t do that. We are functional programmers, so we never tackle
the ultimate goal at once. It’s overwhelming, we’ll most likely fail,
we acknowledge this. Instead, we break it into smaller goals, we
solve each of them perfectly, and finally we compose these small
excellent solutions into a bigger one that addresses the big picture,
which will be an excellent one too, for excellence composes.

So, how we can break this problem into smaller parts? On the one
hand, we have the matter of parsing the Natural numbers
themselves. We already solved that using naturalFromString, great.
On the other hand, we have the issue of that comma ,, which we
haven’t talked about yet. Well, let’s.

The first thing to acknowledge is that we are not really interested in


the comma itself, but rather, in the two Strings that remain when
we split our input String right where the comma is. As soon as we
do that, we will have at our disposal two Strings that we can feed as
input to two separate applications of naturalFromString. So,
apparently we’ll need a function to split a String in two as soon as it
encounters a comma.

splitAtComma :: String -> Maybe (String, String)


splitAtComma "" = Nothing
splitAtComma (',' : cs) = Just ("", cs)
splitAtComma (c : cs) =
case splitAtComma cs of
Nothing -> Nothing
Just (pre, pos) -> Just (c : pre, pos)

This function returns Just the prefix and suffix surrounding the
comma as long as there is a comma somewhere in the input String.
Otherwise, it returns Nothing.

> splitAtComma ""


Nothing
> splitAtComma "abcd"
Nothing
> splitAtComma ","
Just ("","")
> splitAtComma "ab,"
Just ("ab","")
> splitAtComma ",cd"
Just ("","cd")
> splitAtComma "ab,cd"
Just ("ab","cd")

And it works for infinite Strings too —yes, a String can be infinite
like any other list— seeing how splitAtComma produces a result as
soon as it encounters a comma without having to force the spine of
the suffix first. Obviously, if the given list is infinite and there is no
comma in it, splitAtComma will diverge just like and did, wanting for
an absent False. But if there is a comma somewhere, we will get a
finite prefix and an infinite suffix as result.

Is splitAtComma a parser? Sure, why not.


127. Guards
splitAtComma, or, more generally, the idea of splitting a String at a
particular Char, seems useful beyond our twoNaturalsFromString
example. Maybe we could generalize it a bit and allow the string to
be split at the first encounter of any Char we desire, not just comma
,. Yeah, let’s do that. Let’s call this new function splitAtChar, and
while we are at it, let’s introduce some new Haskell syntax.

splitAtChar :: Char -> String -> Maybe (String, String)


splitAtChar _ "" = Nothing
splitAtChar x (c : cs)
| c == x = Just ("", cs)
| True = case splitAtChar x cs of
Nothing -> Nothing
Just (pre, pos) -> Just (c : pre, pos)

Those things delimited by vertical bars | are what we call guards,


and they complement patterns. Whereas a pattern like c : cs or ""
somehow reflects the structure of an expression, guards are Bool
expressions checked for truth after their corresponding pattern has
matched. They are responsible for deciding whether to proceed to
the right-hand side of the equation or not. In our example, after we
successfully pattern-match against the cons : constructor, giving
the names c and cs to its payloads, we check whether c is equal to x,
the Char by which we want to split our String. If it is, then we
proceed to the right-hand side of the single equals sign = and return
Just ("", cs). Otherwise, if c == x is False, we move on to checking
whether the next guard is True. In our case, this second guard will
always be True because that’s what we wrote literally, so if the first
guard failed, this second one will most certainly succeed, allowing
us to proceed to the right-hand side of this equation.
We can have as many guards as we want. Here, two guards suffice.
If none of the predicates in these guards succeed, then the pattern-
matching continues in the next equation as usual. We can also use
guards in case expressions. Other than the syntax being a bit
different, they work exactly the same way. For example, here is
splitAtChar written using a case expression, rather than multiple
equations.

splitAtChar :: Char -> String -> Maybe (String, String)


splitAtChar x s = case s of
"" -> Nothing
c : cs
| c == x -> Just ("", cs)
| True -> case splitAtChar x cs of
Nothing -> Nothing
Just (pre, pos) -> Just (c : pre, pos)

Of course, these guards are not limited to comparing things for


equality using (==) as we did here. We can use any expression that
returns a Bool right after the vertical bar |.

We could now redefine splitAtComma as a partial application of


splitAtChar ',', but frankly, we don’t think splitAtComma deserves a
name of its own, so let’s just discard it and use splitAtChar ','
directly when necessary.
128. Æ
We finally have all the pieces we need to write our
twoNaturalsFromString parser now, so let’s just do it.

twoNaturalsFromString
:: String -> Maybe (Natural, Natural)
twoNaturalsFromString = \s ->
case splitAtChar ',' s of
Nothing -> Nothing
Just (a, b) ->
case naturalFromString a of
Nothing -> Nothing
Just na ->
case naturalFromString b of
Nothing -> Nothing
Just nb -> Just (na, nb)

Unfortunately, this works. I mean, of course it works. This is


functional programming, why wouldn’t it? If the parts work, the
whole works too.
> twoNaturalsFromString ""
Nothing
> twoNaturalsFromString "a"
Nothing
> twoNaturalsFromString ","
Nothing
> twoNaturalsFromString "1,"
Nothing
> twoNaturalsFromString ",2"
Nothing
> twoNaturalsFromString "1,2"
Just (1,2)
> twoNaturalsFromString "12,34"
Just (12,34)

However, it has some problems. First, it’s ugly. Sure, it is


straightforward to understand what goes on line by line if that’s
what we care about: If this, then that, otherwise nothing. If this, then
that, otherwise nothing. Go on then, clap your hands, or can’t you
hear the band marching? If this, then that, otherwise nothing. Of
course we want that to happen eventually, maybe, but we don’t
really want to express it in these terms ourselves. No, we didn’t sign
up for this. All we want to say is “a number, a comma, another
number” and have the computer figure out the tiny marching
details for us, the error handling, the sequencing.

In programming, in mathematics, we can almost just trust


aesthetics. They are mostly right. We will deal with this marching
matter soon. Not immediately, though, because we have more
pressing issues.
129. Compost
While twoNaturalsFromString successfully accomplishes its goals, it
does it in a very steampunk, hardwired way. What if rather than
two Natural numbers, for example, we wanted to parse a Natural
number and the name of a Season separated by a comma? Would we
need to do everything from scratch again? No, we would very much
prefer to tackle the structure of the input String using the same
approach as twoNaturalsFromString, only changing the particulars of
how to parse the prefix and suffix Strings surrounding the comma.
So let’s see if we can abstract those things away, if we can take them
as function parameters, as inputs.

twoSeparateThings
:: (String -> Maybe a)
-> (String -> Maybe b)
-> String
-> Maybe (a, b)
twoSeparateThings = \fya fyb s ->
case splitAtChar ',' s of
Nothing -> Nothing
Just (a, b) ->
case fya a of
Nothing -> Nothing
Just na ->
case fyb b of
Nothing -> Nothing
Just nb -> Just (na, nb)

Alright, this is better. In a sense uglier, but better, for we can reuse
twoSeparateThings to implement parsers like twoNaturalsFromString
and similar on top of this core without repeating ourselves.
twoNaturalsFromString
:: String -> Maybe (Natural, Natural)
twoNaturalsFromString =
twoSeparateThings naturalFromString naturalFromString

Let’s take a look at the type of twoSeparateThings again, adding some


superfluous parentheses here and there.

twoSeparateThings
:: (String -> Maybe a)
-> (String -> Maybe b)
-> (String -> Maybe (a, b))

There is something beautiful about this type, isn’t there? We are, in


a strange way, composing two separate parsers for a and b into a new
parser for both a and b. Yes, it is quite beautiful. We must be onto
something.
130. Leftovers
Something is still wrong with twoSeparateThings. Its type is fine, but
its behavior is not. Think about how twoSeparateThings operates.
First, it looks for a comma in a String, and only after it has found
this character, it proceeds to run the parsers for a and b. At times,
this is fine, but generally speaking, this is not the order in which we
want to do things. If we are describing our parsers from left to right
—parse a, a comma, and then b— maybe we would also like them
to be executed from left to right. It should be easy to see why we
might want to do this if we consider that the parser for a may itself
require a comma. It could be trying to parse geographical
coordinates, say, which are often written as “latitude, longitude”,
but twoSeparateThings would never feed a comma as input to this
parser because it considers it a kind of separator, and not part of the
String that shall become the input to the coordinate parser. No, this
is not the order in which we would like our parsers to be executed.
We want to look for a first, then the comma, and then b. How do
we achieve this?

Let’s say the String we want to parse represents a pair of a Natural


number and a Bool like (352, t) encoded as "352t", where "352"
represents the Natural and the trailing "t" represents True.

As before, we don’t want to write a big steampunk parser that goes


from zero to (Natural, Bool) in one go. Instead, we would like to
write a smaller parser that deals with a Natural, another one that
deals with a Bool, and then compose them somehow so that one runs
after the other. Obviously, we need to implement the individual
parsers for Natural and Bool, but more importantly, we need to
implement the function that composes them so that they run one
after the other, pairing their results. Luckily for us, we already came
across the ideal type this composition function should have.

composeParsers
:: (String -> Maybe a)
-> (String -> Maybe b)
-> (String -> Maybe (a, b))

If we imagine a being Natural and b being Bool, we can see how this
should be able to handle the parsing of our (Natural, Bool) pairs.
Yes, this should work.

This time, however, we don’t have an obvious separator between


"352" and "t" like the comma from before, so we can’t readily split a
String to run the two parsers on the resulting two chunks. And, yes,
sure, we could peek at the input String and say “split it at the first
non-digit character” or something like that, but if we did that, we’d
be violating parametricity. Look at the type of composeParsers again.
It says that it should parse a and b, which could be anything.
Remember, a and b are universally quantified. So no, we can’t
make assumptions about how to split the input String based on our
current needs for Natural and Bool. So, what do we do?

Well, think about how we’d address this problem if we were


discussing it out loud with a friend. We’d say we run the parser for
a first, consuming as much input as necessary, and then we run the
parser for b on any input that was not consumed by a's parser. That
is, in the concrete case our Natural and Bool parsers dealing with
inputs like "352t", the first parser, the Natural one, would consume
the "352" prefix decoding it as the Natural number 352, and
afterwards the Bool parser would consume that leftover "t", trying
to decode something meaningful from it, like True. Well, this is
exactly how parser composition should happen in our program. We
need to write our parsers in a way that not only do they result in
successful values like 352 or True, but also they resist the temptation
of trying to consume all the input that was provided to them.
Instead, they should consume as little as possible in order to achieve
their goal, and then return both the successful parsing result and
any input they didn’t consume as leftover. And yes, we call these
leftovers “leftovers”. That’s a technical term.

Let’s start by writing a parser for Bool that takes leftovers into
account. We want the String "t" to become True, we want "f" to
become False, and anything else should fail parsing.

parseBool :: String -> Maybe (String, Bool)


parseBool ('t' : z) = Just (z, True)
parseBool ('f' : z) = Just (z, False)
parseBool _ = Nothing

Well, that was easy. Notice how our parser doesn’t just return Bool
anymore. It now returns any unused leftovers as well. Which, by
the way, could be the empty String if that’s all what’s left in the
input String after consuming that first Char. Why not?

It’s important to highlight that the leftovers must always be an


unmodified suffix of the input String. That is, if our parser
consumes something from the input String in order to successfully
produce an output, this must be an entire prefix of the input String,
and the returned leftovers must be the suffix that was not
consumed, unmodified. Otherwise, composing these parsers one
after the other would behave unpredictably.
131. Two
With the introduction of leftovers, we’ve changed the type of our
parsers. Rather than a parser for some type x having this type:

∀ x. String -> Maybe x

We now have this other type, which also includes leftovers as part
of the result:

∀ x. String -> Maybe (String, x)

Thus, we need to change the type of composeParsers to


accommodate this.

composeParsers
:: (String -> Maybe (String, a))
-> (String -> Maybe (String, b))
-> String
-> Maybe (String, (a, b))

The type looks uglier because we temporarily removed the


redundant parentheses to make a point. The idea is that
composeParsers will first use that standalone String as input to the
parser for a, and then, if that parser succeeds, it will provide any
leftovers to the parser for b as input, whose own leftovers will
become the leftovers of the entire composition. Implementing this
is quite straightforward.
composeParsers
:: (String -> Maybe (String, a))
-> (String -> Maybe (String, b))
-> (String -> Maybe (String, (a, b)))
composeParsers pa pb = \s0 ->
case pa s0 of
Nothing -> Nothing
Just (s1, a) ->
case pb s1 of
Nothing -> Nothing
Just (s2, b) -> Just (s2, (a, b))

This is nice. And yes, we still have the marching “if this, then that,
otherwise nothing” from before, but the difference is that
composeParsers will be the last time we ever write this. One of them,
anyway. From now on, we will use composeParsers to, well, compose
parsers, and all of this will happen behind the scenes without us
having to care about it. Lovely.

Does it work? Sure, why wouldn’t it? For example, here is a parser
that parses two Bools, one after the other.
> parseTwoBools = composeParsers parseBool parseBool
> :t parseTwoBools
parseTwoBools :: String -> Maybe (String, (Bool, Bool))
> parseTwoBools ""
Nothing
> parseTwoBools "t"
Nothing
> parseTwoBools "tt"
Just ("", (True, True))
> parseTwoBools "ft"
Just ("", (False, True))
> parseTwoBools "ttfx"
Just ("fx", (True, True))
132. Wot
Still wearing your subversive hat? Pick it up, you’ll need it, go on.

Notice how nothing in the type of composeParsers mandates that a


gets parsed before b.

composeParsers
:: (String -> Maybe (String, a))
-> (String -> Maybe (String, b))
-> (String -> Maybe (String, (a, b)))

We are making an arbitrary choice here when we say that a will be


parsed before b, when we say that the leftovers from parsing a will
become the input for b's parser. This is our choice, and we like it
because it coincides with the intuition that we are parsing things
from left to right: The leftmost input parameter to composeParsers,
the parser for a, will be used before its rightmost input parameter.

But still, even if we make that choice, nothing in the types prevents
us from accidentally running the parser for b first. Here is the
proof, look.
composeParsers
:: (String -> Maybe (String, a))
-> (String -> Maybe (String, b))
-> (String -> Maybe (String, (a, b)))
composeParsers pa pb = \s0 ->
case pb s0 of
Nothing -> Nothing
Just (s1, b) ->
case pa s1 of
Nothing -> Nothing
Just (s2, a) -> Just (s2, (a, b))

See? This implementation looks quite similar to the allegedly


correct one one from before, but this time we are using b's parser pb
first, and only after pb succeeds, if it succeeds, we run pa on pb's
leftovers.

The problem is in those Strings. Since both pa and pb take Strings as


input, composeParsers is allowed to use the String it receives, s0, as
input to any of pa or pb. The fate of s0 is not determined by the type
of composeParsers. But what if it was?

We know that our parsers are ultimately expected to take Strings as


input. But if we pay close attention to composeParsers, we’ll notice
that nothing in its implementation is specific to Strings. We can
notice this by either using our brains to think about it, or by not
explicitly writing a type for our correct composeParsers, instead
asking Haskell to infer it for us.
composeParsers
:: (x -> Maybe (y, a))
-> (y -> Maybe (z, b))
-> (x -> Maybe (z, (a, b)))

What changed was that all the Strings were replaced by universally
quantified type variables x, y and z. And crucially, we can see now
how the input to b's parser matches the type of the leftovers from
a's parser, which will force the execution of the parser for a to
happen before that of b's. This is beautiful.

Moreover, we accidentally freed our parsers from the constraint


that they must all consume Strings and have Strings as leftovers too.

foo :: [Bool] -> Maybe (String, Season)

bar :: String -> Maybe (Natural, Decimal)

qux :: [Bool] -> Maybe (Natural, Decimal)


qux = composeParsers foo bar

We won’t be embracing this freedom we accidentally fought for.


It’ll be our leftover. We will, nonetheless, still use the parametrically
polymorphic composeParsers because it helps with our reasoning,
because it leads to outstanding type-inference and type-checking
error messages, and because it works with Strings just fine.

The idea to take away from this exercise is that even if we ultimately
intend to limit our concrete use cases to just one, we may not
actually need to limit our reasoning to that one case. In our types,
through parametric polymorphism, we can convey meaning and
determine the fate of our expressions in ways that with concrete
types, also known as monomorphic types, we just can’t.

Of course, none of this is news for us. We saw it back when we


discovered polymorphic function composition, or when we
realized how mapping a function over a list, over a Maybe or over
another function, could be generalized as a Functor, which gave us
both freedom and constraint at the same time. Parametric
polymorphism is almost always a good idea.

But we are not fully polymorphic in composeParsers, are we? Most


notably, we still have a Maybe as the return type, which technically
enables us to return Nothing at any point without doing any work.
We’ll get there, don’t worry, we’ll get rid of that too.
133. Twogether
It’s worth noticing how composeParsers seems to be composing
things in two different ways at the same time.

composeParsers
:: (x -> Maybe (y, a))
-> (y -> Maybe (z, b))
-> (x -> Maybe (z, (a, b)))

On the one hand there is the composition of a and b into the pair
(a, b). This is not particularly surprising for us, considering how
achieving this composition, this pairing, was our goal all along. This
composition is merely the result of using the tuple constructor (,)
on a and b to form a new product type (a, b).

(,) :: a -> b -> (a, b)

But if we forget about a and b for a moment, we will find that


there’s another composition going on too, a more interesting one.
In order to appreciate this more clearly, let’s remove every mention
of a and b from the type of composeParsers.

(x -> Maybe y) -> (y -> Maybe z) -> (x -> Maybe z)

Does it remind you of something? Maybe it’s easier to see if we just


hide those Maybes.

(x -> y) -> (y -> z) -> (x -> z)

Indeed, this is just normal function composition. The order of the


parameters is flipped, but we still have a function from x to y,
another from y to z, and we are composing them to build a new
function from x to z. What does this mean?

We need to remind ourselves of how we got here. We came up with


this type because we wanted to establish an ordering between our
parsers for a and b. A semantic ordering that forced a to be parsed
before b, passing around their leftovers accordingly. Well,
composition is how we order things in programming. Think about
it. A function a → b says that if an a exists, then b can exist too.
Then. That’s the crucial word.

And we may be tempted to think that laziness somehow invalidates


this line of reasoning, seeing how things will only be evaluated
when needed, not necessarily in the same order in which they
appear in the types. However, evaluation order is not what we are
considering here, and if anything, the fact that the a in a → b
completely submits its evaluation to the whims of b only reinforces
the idea that a exists before b. Conceptually, at least.

So, yes, in composeParsers we somehow managed to create


something that composes two different things in two different
ways at the same time. On the one hand, it uses (,) to pair a and b,
and on the other hand it uses function composition, conceptually
at least, to tie x, y and z together.
134. Tres
But what about those Maybes we neglected? Let’s go back to them,
rearranging the type a bit so that it resembles (.) as much as
possible, and giving the whole thing a name.

composeMaybes
:: (y -> Maybe z)
-> (x -> Maybe y)
-> (x -> Maybe z)

This looks quite like function composition, doesn’t it? However,


our functions are a bit funny this time. Rather than going straight
from one type to the other, they wrap their output type in a Maybe
to indicate the possibility that there could not be a meaningful
output at all. This is fine. For example, we know that when we
compose two parsers using composeParsers, each of them could fail,
they could result in Nothing, making their whole composition fail as
well. But even beyond parsers, any two functions that return a
Maybe as output could be composed in this way. For example,
consider these two:

foo :: Natural -> Maybe Char

bar :: Char -> Maybe Digit

It doesn’t matter what these functions do, what matters is that foo's
Char output, if any, could serve as bar's input, and that either foo or
bar could fail at whatever it is that they do, resulting in Nothing,
which will make their composition return Nothing too, either
because there is no Digit, or because there’s no Char. So, yes, failure
composes too.

qux :: Natural -> Maybe Char


qux = composeMaybes bar foo

It’s rather obvious what composeMaybes should do, isn’t it?

composeMaybes
:: (y -> Maybe z)
-> (x -> Maybe y)
-> (x -> Maybe z)
composeMaybes g f = \x ->
case f x of
Nothing -> Nothing
Just y -> g y

So, while in a normal function composition g . f we know that g


will always be performed, composeMaybes g f may perform g or not,
depending on whether f returns Nothing or Just. And of course, just
like in normal function composition, there is an order to this
composition too. f must happen before g, for g takes as input a y
that can only be obtained from a successful application of f.

So, it turns out that composeParsers was actually performing three


compositions at the same time. Tres. The parsing results, the
inputs, and the failures, all of them were being composed in
different ways. Composition, that’s what matters. We humans have
a tendency to focus on things, but in reality, it’s the relationship
between things what matters. And this book, in case you hadn’t
noticed, is about that.

But composition is terribly uninteresting unless we have identities


to compose, too. Without them, say, we could have a broken
implementation of composeMaybes that always results in Nothing.
Identities prevent these silly things. In the case of composeMaybes, this
identity is Just.

composeMaybes Just f == f

composeMaybes f Just == f

In the case of function composition —like the one we kinda see in


our leftover management— the identity is obviously id. We know
this.

id . f == f

f . id == f

But what about the identity when pairing two things using (,), as
we are doing with our parser outputs a and b?

(‽, x) == x

(x, ‽) == x

Ah, wouldn’t we like to know? There must be an identity,


otherwise we wouldn’t be calling this product a “composition”. We
will learn about it, but not right away. First, we have something to
wrap up.
135. To wrap up
We know that we want all our parsers to have the type String →
Maybe (String, x), where x is something meaningful we hope to
obtain from this String. For example, here’s the implementation of
our most recent parseBool using this type.

parseBool :: String -> Maybe (String, Bool)


parseBool = \s ->
case s of
't' : z -> Just (z, True)
'f' : z -> Just (z, False)
_ -> Nothing

But actually, we like the type of functions like these so much that
we want it to be its own different type.

data Parser x = Parser (String -> Maybe (String, x))

We have seen datatypes like this one before, having just one
constructor and carrying a function as a payload. Op, for example,
was one of them.

data Op a b = Op (b -> a)

They are very common when we want to give functions with a


particular shape, serving a particular purpose, a distinct type so that
we can more easily talk and reason about them, while at the same
time we distinguish them from other functions that would
otherwise have the same type yet serve a different purpose. The idea
is that rather than talking about “parseBool, the function that takes
a String and returns a Maybe (String, Bool) where Nothing conveys
parsing failure and Just conveys a successful parsing of a Bool
accompanied by a leftover input String”, we will assign a meaning
to the Parser type, and then just talk about “parseBool, the Parser of
Bool values”.

parseBool :: Parser Bool


parseBool = Parser (\s ->
case s of
't' : z -> Just (z, True)
'f' : z -> Just (z, False)
_ -> Nothing)

Two things changed in this definition of parseBool compared to the


one from before. First, the type. Just look at it, Parser Bool,
beautiful, all the noise is gone. Second, we are wrapping the entire
\s → … function from before inside the Parser constructor. That is,
this function becomes the sole payload of this datatype.

Remember, there is a type-constructor called Parser, of kind Type →


Type, which we can apply to a Type like Bool to obtain yet another
Type, Parser Bool. We can construct values of type Parser Bool —or
Parser whatever, really— by using the value-constructor also called
Parser, of type (String → Maybe (String, Bool)) → Parser Bool,
where String → Maybe (String, Bool) is exactly like the type of our \s
→ … expression.

Here is a different Parser that does something else. A boring one


that always fails to parse any x we ask of it.

fail :: ∀ x. Parser x
fail = Parser (const Nothing)
Does it type-check? Indeed it does, const Nothing has type ∀ a b. a
→ Maybe b, so if we pick String as our a, and (String, x) as our b,
everything will click. It is is not the most interesting Parser, but it is
a Parser nonetheless.

So, what do we do with these Parsers? Well, the same thing we did
with them back when they were still functions: We provide some
input to them and see what happens. Doing this when parsers were
functions was easy, all we had to do was apply them to an input
String, that was all. But what can we do now? A Parser is not a
function anymore. Or is it? Sure, at a very superficial level, a Parser
x is not a function, but if we look beyond that Parser wrapper, all
we’ll find is a plain old boring function taking String as input and
returning Maybe (String, x) as output. So, presumably, what we
need to do is somehow remove the Parser wrapper and provide the
String input directly to the underlying function.

We are not strangers to this approach, actually. For example, we


saw something similar in Sum, remember?

data Sum = Sum Natural

You see, there is a Natural value inside the Sum value constructor, but
in order to operate on it directly, we first need to remove the Sum
wrapper. In fact, we introduced a function named unSum just for
this.

unSum :: Sum -> Natural


unSum (Sum x) = x

Hmm, what would happen if we did the same thing to Parser?


unParser :: Parser x -> (String -> Maybe (String, x))
unParser (Parser f) = f

Of course, unParser gives us the function within the Parser value-


constructor, which, being a function, can now be applied to its
input String by juxtaposition as usual. Traditionally, people call
functions like these, which when fully applied to all of its input
arguments give the impression of running the Parser or similar
somehow, runSomething, rather than unSomething. Maybe we
should do that as well, out of respect for tradition. And we will
remove the redundant rightmost parentheses while we are at it.

runParser :: Parser x -> String -> Maybe (String, x)


runParser (Parser f) = f

We can now talk about runParser, the function that runs the given
Parser on the given String, resulting in a parsing result and parsing
leftovers, if any.

> runParser parseBool "t"


Just ("", True)
> runParser parseBool "tf"
Just ("f", True)
> runParser parseBool "x"
Nothing
> runParser fail "hello"
Nothing

Excellent. The only important thing left to worry about is


composeParsers, which should now deal with values of type Parser
rather than the String-taking parsing functions from before.
composeParsers :: Parser a -> Parser b -> Parser (a, b)
composeParsers pa pb = Parser (\s0 ->
case runParser pa s0 of
Nothing -> Nothing
Just (s1, a) ->
case runParser pb s1 of
Nothing -> Nothing
Just (s2, b) -> Just (s2, (a, b)))

Look at that handsome type, all the noise is gone. All we did was
replace the previous parsing functions for values of type Parser, use
runParser each time we need to run a Parser on some input, and
finally wrap the entire expression in a Parser value constructor. The
rest is the same as before. Well, almost. We lost some of the
parametricity we had, seeing how the Parser datatype fixes the
parsing input and leftover types to be Strings, so we can’t tell
anymore the order in which of these Parsers are run just by looking
at the type of composeParsers. We now need to rely on
documentation, routine and prayer. It’s alright, though. Even
though we made a big deal out of this before, that was mostly to
make a point. In practice, this is a minor issue. In Haskell, tradition
says things go from left to right, so that’s the order in which we
normally expect things to happen unless something says otherwise.

> runParser (composeParsers parseBool parseBool) "tfx"


Just ("x", (True, False))
> runParser (composeParsers parseBool parseBool) "txf"
Nothing

However, if we cared enough we could bring back that lost


polymorphism to the Parser type.
data Parser i o x = Parser (i -> Maybe (o, x))

In this type, i is the parser’s input type, o is the parser’s leftover


type, and x is the actual parsing output. The implementation of
composeParsers would be exactly the same, only its type would
change.

composeParsers
:: Parser x y a
-> Parser y z b
-> Parser x z (a, b)

We won’t be doing any of this, though. We could, but to keep


things “simple”, we’ll just embrace the left to right tradition.
136. Cardinality
Why is a product type called a product type? Why is a sum type
called that? In part it has to do with their cardinality, that is, with
the number of values that can potentially be of these types. Or, as
we say, the number of values that inhabit them. Let’s start with
something simple, let’s start with Bool.

data Bool = True | False

The cardinality of Bool is two because Bool has only two inhabitants
True and False. And what if we pair two Bools in a product type?
What would be the cardinality of that pair?

(Bool, Bool)

It’s four, of course. We can verify this by explicitly enumerating all


of the possible values of type (Bool, Bool) —(True, False), (True,
True), (False, False) and (False, True)— or by simply multiplying
the cardinalities of the types that are part of this pair.

2 × 2 == 4

Multiplication, product. From here product types take their name.


But four is also the sum of two and two, isn’t it?

2 + 2 == 4

It is, and we can see this manifest itself as the cardinality of a sum
type of Bools, each of them having a cardinality of two.
Either Bool Bool

Again, there are four values that could have type Either Bool Bool.
They are Left False, Left True, Right False and Right True. From
here, sum types take their name. Interestingly, the cardinalities of
(Bool, Bool) and Either Bool Bool are equal.

2 + 2 == 2 × 2

And surprisingly perhaps, this implies that (Bool, Bool) and Either
Bool Bool are isomorphic. That is, we can convert between values of
these two types back and forth without any information loss. Here
is one proof of this.

fromEither :: Either Bool Bool -> (Bool, Bool)


fromEither (Left x) = (False, x)
fromEither (Right x) = (True, x)

fromPair :: (Bool, Bool) -> Either Bool Bool


fromPair (False, x) = Left x
fromPair (True, x) = Right x

Composing these functions, as expected of every isomorphism,


results in identities.

fromEither . fromPair == id

fromPair . fromEither == id

In general, for any two datatypes having the same cardinality, we


can always come up with a pair of functions that proves that an
isomorphism exists between them. Or more than one, perhaps. For
example, rather than using the Left constructor whenever the first
Bool in the pair is False, we could have chosen to use the Right
constructor:

fromEither2 :: Either Bool Bool -> (Bool, Bool)


fromEither2 (Right x) = (False, x)
fromEither2 (Left x) = (True, x)

fromPair2 :: (Bool, Bool) -> Either Bool Bool


fromPair2 (False, x) = Right x
fromPair2 (True, x) = False x

These two functions form an isomorphism too. Is this a better


isomorphism than the one given by our previous fromPair and
fromEither? No, nor is it a worse one. It’s just different.
137. Injection
We said interesting things about functions seen together as
isomorphisms, but we can also say interesting things about them on
their own. Let’s look at fromPair, for example. What can we say
about it?

fromPair :: (Bool, Bool) -> Either Bool Bool


fromPair (False, x) = Left x
fromPair (True, x) = Right x

If we pay attention to the output of this function, we can see that it


is a surjective one. Its codomain, comprising all the possible values
of type Either Bool Bool, equals the image of this function, by
which we mean the values of type Either Bool Bool that this
function actually outputs. So, yes, fromPair is surjective.

But if we also include the input type in our reasoning, there’s


something else we can say about fromPair. Notice how each value in
the domain of this function, (Bool, Bool), has a distinct
corresponding value in its codomain. No two different input values
result in a same output value, which ultimately leads the cardinality
of its domain, four, to be equal to the cardinality of its image. We
call this property injectivity, we say that fromPair is an injective
function.

And yes, talking about the cardinality of the image of a function is


fine. Generally speaking, cardinality is a property of sets, and it’s
mostly just a fancy name for talking about how many elements are
in a set. If you have five friends, lucky you, then the cardinality of
your set of friends is five.
For contrast, here is a non-injective function.

isEmpty :: [a] -> Bool


isEmpty [] = True
isEmpty _ = False

isEmpty is not injective, for some elements of its domain —namely,


all the non-empty lists— map to a same element of its image, False.
This is a surjective function, but it is not an injective one.

And why is injectivity good? Well, it’s neither good nor bad, it’s
just a property. Like enjoying a particular song or having been born
in June, it doesn’t say much about us.
138. Invert
What’s interesting for us is that when a function is both injective
and surjective, this function is said to be bijective, and all bijective
functions have an inverse function which, essentially, undoes
everything the bijective function did. We can also call these inverses
anti-functions, but only if we like science fiction.

In our example, fromPair is a bijective function and fromEither is its


inverse. Or, taking the opposite perspective, we can say that
fromEither is our bijective function and fromPair its inverse.
Generally, we just say these two functions are inverses of each
other, and this implies their bijectivity.

And all of this for what? Because this is what an isomorphism is: A
pair of functions that are the inverse of each other. That’s it. At
least insofar as types and functions are concerned.
139. Broken parts
A product type multiplies the cardinalities of its parts, a sum type
adds them. So what?

It turns out that there is a direct correspondence between our data


types and algebraic expressions like 2 + 4 or 3 × a. That is, we can
translate many algebraic expressions to a type and vice-versa. So
much so, actually, that we call these things algebraic data types.

For example, the Either sum type applied to two types a and b
having a particular cardinality, corresponds to the addition of the
two natural numbers representing those cardinalities. Say, if we
acknowledge that the cardinalty of Bool is two, and that the
cardinality of Season is four, then the algebraic expression adding
these two numbers corresponds, in Haskell, to a use of Either on
the corresponding types Bool and Season.

2 + 4 == Either Bool Season

And indeed, if we were to count it manually, we’d find the


cardinality of Either Bool Season to be six.

Notice that in our use of the symbol ==, we are not saying that these
things are equal. They couldn’t possibly be equal because we have
numbers on one side and types on the other. All we are saying is
that there is a correspondence between these algebraic expressions
and these types.

But more generally, leaving the field of arithmetic and jumping


deep into algebra, we can replace 2 and 4 with almost any other
algebraic expressions a and b and the correspondence would still
hold.

a + b == Either a b

And similarly, we have product types, or pairs, corresponding to


algebraic multiplication:

a × b == (a, b)

Which of course we could further compose with algebraic addition:

a × (b + c) == (a, Either b c)

And, if you recall from elementary school, multiplication had this


interesting property of being distributive over addition, meaning
that for all choices of a, b and c, the following two algebraic
expressions are equal:

a × (b + c) == (a × b) + (a × c)

Which, of course, can both be represented as types, since they are


just addititons and multiplications which in Haskell correspond to
Eithers and pairs.

(a, Either b c) ≈ Either (a, b) (a, c)

Now, these two types are not exactly equal. If we pass a value of
type (a, Either b c) to a function expecting a value of type Either
(a, b) (a, c), our program will fail to type-check. But they are
isomorphic, as signaled by our usage of the symbol “≈” above, and as
proved by this pair of inverse functions.

foo :: (a, Either b c) -> Either (a, b) (a, c)


foo (a, Left b) = Left (a, b)
foo (a, Right c) = Right (a, c)

bar :: Either (a, b) (a, c) -> (a, Either b c)


bar (Left (a, b)) = (a, Left b)
bar (Right (a, c)) = (a, Right c)

But the correspondence between algebraic data types and algebra


doesn’t end here. Look at what happens when we start mixing
numbers with variables.

1 + a == Maybe a

Maybe? How? Well, let’s recall its definition and see for ourselves.

data Maybe a = Nothing | Just a

That is, a value of type Maybe a can be constructed by using Nothing


or by applying Just to a value of type a, of which we have as many
inhabitants as its cardinality says we have. So, if we take Maybe Bool
for example, we would have three ways of constructing a value of
this type, namely Nothing, Just False and Just True. In other words,
Maybe Bool corresponds to the number 3.

3 == 1 + 2 == Maybe Bool

Using this same line of reasoning, we can come up with an algebraic


datatype of any cardinality we want. For example, a while ago we
came up with a Digit type because we needed something of
cardinality ten. But isn’t ten just another natural number that can
be expressed as additions and products of some other numbers?
Sure it is, and we can use an approach not unlike equational-
reasoning to explore this, playing fast and loose with the fact that
we are intertwining algebraic expressions, numbers and types.

Digits
== 10
== 2 × 5
== Bool × 5
== Bool × (Bool + 3)
== Bool × (Bool + (1 + 2))
== Bool × (Bool + (1 + Bool))
== Bool × (Bool + Maybe Bool)
== (Bool, Either Bool (Maybe Bool))

And yes, we could have factorized 10 in a different way, eventually


arriving at a different datatype. Different, but still isomorphic.

Are Digit and (Bool, Either Bool (Maybe Bool)) isomorphic? Well,
they better be. If we are able to come up with a bijective function
from Digit to (Bool, Either Bool (Maybe Bool)) we will have proved
this, seeing how every bijection has an inverse, and together they
form an isomorphism.
fromDigit :: Digit -> (Bool, Either Bool (Maybe Bool))
fromDigit D0 = (False, Left False)
fromDigit D1 = (False, Left True)
fromDigit D2 = (False, Right Nothing)
fromDigit D3 = (False, Right (Just False))
fromDigit Dog = (False, Right (Just True)) -- Woof!
fromDigit D5 = (True, Left False)
fromDigit D6 = (True, Left True)
fromDigit D7 = (True, Right Nothing)
fromDigit D8 = (True, Right (Just False))
fromDigit D9 = (True, Right (Just False))

Is fromDigit injective? Yes, it takes each element from its domain to a


distinct element of its image. Is it a surjective function? Yes, its
image and codomain are the same. Is fromDigit a bijective function?
Yes, for it is both injective and surjective. Does fromDigit have an
inverse? Yes, every bijective function is invertible, although quite
often the inversion is an exercise for the reader. Are Digit and (Bool,
Either Bool (Maybe Bool)) isomorphic? Yes, for there are two
functions, fromDigit and its inverse, that are by definition inverses
of each other. Is it the only isomorphism between these types? No,
we made many arbitrary choices when we came up with our
mapping between these types, and we could have chosen
differently.

So, why do we come up with types like Digit if Eithers, pairs, Bools
and the like seem to be enough? Well, humans, that’s why.
Internally, computers and programming languages use simple sum
and product types like Either and pair a lot. Digit, ten, Either Bool
(Maybe Bool), 3 + 7, 10, it doesn’t matter what we call it, computers
don’t care. But we humans, we care about names. The words
“digit” or “season” mean something to us, so we come up with
technically irrelevant stuff like names in order to improve our
quality of life, and that’s fine.
140. Unit
What about the one? That is, one, literally.

It’s quite straightforward, actually. It barely deserves any attention.

data Unit = Unit

See? One constructor, cardinality one, done. Next topic.

> :t Unit
Unit :: Unit
141. Plus one
Just kidding. Of course there’s more to Unit than its definition. For
example, we recently said that the algebraic expression 1 + a
corresponds to the Haskell datatype Maybe a. But that’s not the sole
truth, is it? If we are saying that Unit corresponds to one, and that
Either corresponds to addition, then what’s wrong with this?

1 + a == Either Unit a

Nothing, there’s nothing wrong with that. Indeed, Maybe a and


Either Unit a are isomorphic. Here’s the proof, this time using the
maybe and either functions rather than pattern-matching, for fun.

fromMaybe :: Just a -> Either Unit a


fromMaybe = maybe (Left Unit) Right

fromEither :: Either Unit a -> Just a


fromEither = either (const Nothing) Just

Now, we know that addition is a commutative operation, meaning


that even if we swap the order of the operands, the result stays the
same.

1 + a == a + 1

This is indeed true in algebra. However, in Haskell, the


corresponding types are not exactly equal, just isomorphic.

Either Unit a ≈ Either a Unit


That is, we can’t just use a value of type Either Unit a where a value
of type Either a Unit or Maybe a are expected, even if algebra says
these are equal.

Bool ≈ Either Unit Unit

Isomorphic, but not equal.


142. Times one
What about multiplying by one?

1 × a == (Unit, a)

Right, of course, multiplication corresponds to product types, to


pairs, so we just pair Unit, one, with our chosen a, and that’s our
answer. However, as before, if we try to exploit the commutativity
of multiplication, we end up with just an isomorphism on the
Haskell side of things, not an equality. That is, while in algebra 1 ×
a and a × 1 are equal, in Haskell types they are just isomorphic.

(Unit, a) ≈ (a, Unit)

Why do we insist on isomorphisms so much? Well, because


something interesting is about to happen. Look at this:

a × 1 == a == 1 × a

Back when we were learning about multiplication of natural


numbers, we learned that one was the identity element or unit of
multiplication, meaning that multiplying a number by this unit
leads back to that same number. Or, more generally, in algebraic
terms, multiplying any variable a by the multiplicative identity, one,
leads back to that same a. And this, of course, has its
correspondence in types too.

(Unit, a) ≈ a ≈ (a, Unit)


This isomorphism is important because equality won’t be enough
where we are going. At times we will end up with (Unit, a) when,
conceptually, a is all we care about.

It’s interesting to reason about why a and a pair of a and Unit are
conceptually equal, isomorphic, even if (a, Unit) clearly has more
information than a, and converting between (a, Unit) and a clearly
loses some information. Namely, Unit.

byeUnit :: (Unit, a) -> a


byeUnit (Unit, a) = a

See? Unit is gone. Poof.

Unit differs from every other type in that it has only one inhabitant,
so if we know that a value has the type Unit, then we also know that
this value must be the constructor also named Unit, simply because
there is no alternative. So if we are asked to come up with the
inverse function of byeUnit, of type a → (Unit, a), we can simply
create the Unit that we need, right there on the spot.

hiUnit :: a -> (Unit, a)


hiUnit a = (Unit, a)

There is simply no other possible implementation of a function


with this type. So byeUnit didn’t really lose any information about
Unit, because there was no information to be lost. Unit can come
and go as necessary. It has no meaning, it’s there simply to fill the
gaps.
143. Equality
In types, equality is a very strong statement. Generally speaking, a
type is only equal to itself.

The idea of types, in Haskell, comes from a nice branch of


mathematics unsuprisingly called Type Theory, or more precisely,
constructive Type Theory, which, as its name indicates, constructs
things. In particular, it constructs truths.

When we define a datatype like Bool, we are saying “this is Bool,


nothing else is Bool, and these are its inhabitants True and False”.
From that point on Bool, True and False exist, and they are different
from anything else that came before them. This is the new truth,
and from this construction follows that Bool is only equal to itself.

But nothing in this construction talks about how Bool could be


considered equal to an isomorphic type, so it is up to us to prove, if
necessary, that any non-Bool type we might be interested in can be
seen as equal to Bool by means of an isomorphism, which in
concrete terms means applying a function to convert between Bool
and this other type in the desired direction. Anything less than that
will fail to type-check.

But if Bool and Either Unit Unit are obviously isomorphic, or more
generally, if any two datatypes with the same cardinality are, why
doesn’t the compiler magically come up with an isomorphism
between them and use that to reason about Bool and Either Unit
Unit as equals? It would be nice, wouldn’t it? They mean the same,
don’t they? Well, you tell me.
data Hire = HireHer | HireHim | HireThem

data Fire = FireHer | FireHim | FireThem

According to their cardinality, these are isomorphic too. Perhaps


we’d like to consider them as equals? No, of course not. To hire
and to fire mean completely different things to us, even while
technically, yes, they are isomorphic.

Hire and Fire are equal in an extensional manner where we only


consider structural matters about types such as their cardinalities,
but they are not equal in an intensional manner by which we assign
meaning to these types beyond what the type-system sees.

So, no, it would not be such a great idea to allow the type-system to
automatically guess whether two types should be treated as equal
based simply on their extensional properties. One could envision a
type system where we explicitly allowed some types to be treated as
equal, such as (Unit, a) and a, even if ultimately they are not. This
is closely related to the idea of univalence, which we won’t be
covering here, but is different from equality and lies at the core of
modern type theories that among other things attempt to tackle
this matter.
144. Mon produit
A while ago we said that the multiplication of natural numbers,
with one as its identity element, was a monoid. And we are saying
now that multiplication corresponds to product types, and that one
corresponds to Unit. Are we implying that product types are
monoids too? Why, of course we are.

Let’s see. What is a monoid? On the one hand, there is an


associative binary operation taking two values of a same type. Do
we have this? Kinda.

(,) :: a -> b -> (a, b)

a and b are most certainly not the same type. They could be, sure,
but their separate universal quantifications say this is not necessary.
But even if a and b were the same type c, say, the output type (c, c)
would still be different to the inputs of type c.

(,) :: c -> c -> (c, c)

So, what? Monoid no more? Not necessarily. Let’s compare the


type of (,) with that of (*), the function that multiplies Natural
numbers —or any Num, really, but we are only considering Naturals
just to keep things simple.

(*) :: Natural -> Natural -> Natural

If we were to describe this function out loud, we would say that (*)
is the function that takes two values of type Natural and outputs yet
another value of type Natural. That is, we are talking about the
things we do to values of type Naturals.

But (,) is not so much the values it receives as input —which, as


mandated by parametricity, remain completely untouched
anyway— but about the types of its inputs and output. We are
talking about product types, not product values. So, not unlike (*)
concerns itself with different values of a same type, (,) concerns
itself with types of a particular kind.

(,) is the binary operation of our monoid, yes, but rather than
taking two values of a same type into another value of that same
type, it takes two types of a same kind into another value of that
same kind. But if we are now talking about types and kinds rather
than values and types, we better look at type constructors, not value-
level functions. In other words, our binary operation is not so
much the value constructor (,) of type a → b → (a, b), but the type
constructor (,) of kind Type → Type → Type.

> :kind! (,)


(,) :: Type -> Type -> Type

Now, this takes us to a very different place. In particular, we won’t


be able to use the Monoid typeclass we explored before because that
was designed to operate on values, not on types. But that’s fine, we
are not actually planning to implement anything, we are simply
exploring some ideas in our mind, beyond Haskell.

So we have (,), a binary operation on types of kind Type. Great. Is it


associative? Well, if we are claiming this is a monoid, it must be.
That is, the type (a, (b, c)) must be equal to the type ((a, b), c).
Now, these types are most definitely not equal, but they are
isomorphic, as proved by the bijective function assoc. And while
this isomorphism wouldn’t make a type-checker happy, it is enough
for us humans to acknowledge the associativity of (,).

assoc :: (a, (b, c)) -> ((a, b), c)


assoc (a, (b, c)) = ((a, b), c)

So we have an associative type-level function (,) operating on types


of kind Type. Do we have an identity element, a unit, of that same
kind Type? This should be a type that, when combined with another
type x, should result in x once again. Well of course we have it, it’s
the Unit type, corresponding to the number one, the identity
element for the product of numbers.

> :kind! Unit


Unit :: Type

And, while not equal, the following types are all isomorphic, which
is good enough for us.

(Unit, a) ≈ a ≈ (a, Unit)

So, yes, we can reason about the product of types as monoids in the
same way we could reason about the product of numbers as
monoids.

And in doing this we kinda left Haskell behind, which brings our
attention to the fact that many of the ideas we are learning,
showing up here as values and types, have a place outside Haskell
too. It’s just that in Haskell they can run, and that makes this place
so particularly interesting.

And by the way, if we really wanted, we could have these type-level


monoids in Haskell too. To a good extent anyway, up to
isomorphisms. Not today, though, for we are learning something
else instead.
145. L’addition
What about addition? We saw that there was a clear
correspondence between the addition of numbers and sum types.
And, seeing how the addition of numbers is a monoid, as we saw
many times before, presumably sum types are a monoid too. Well,
of course they are.

Just like (,), Either is a type-constructor of kind Type → Type → Type.


Is it an associative one? Yes, it is, as witnessed by this invertible
function.

assoc :: Either a (Either b c) -> Either (Either a b) c


assoc (Left a) = Left (Left a)
assoc (Right (Left b)) = Left (Right b)
assoc (Right (Right c)) = Right (Right c)

But what about our identity element, which according to the


addition of natural numbers was zero? Well, it’s just a type with
zero inhabitants, which in Haskell we call Void, presumably to
convey a vast sense of emptyness.

data Void

And no, we didn’t forget anything. We are saying that Void is a new
datatype, but since it has no inhabitants, we are listing no
constructors for it, and this is fine.

So how do we construct a value of type Void? Well, we don’t. That’s


the beauty of it. Void exists as a type, but it does not exist as a value,
which among other things allows us to claim that yes, Void is the
identity element for the addition of types, that is, for Either.
Either Void x ≈ x ≈ Either x Void

How? Well, all we have to do is find the relevant isomorphisms.


Going from x to Either x Void is quite straightforward. We just use
x as payload for the Left constructor and ignore the Right side
completely.

toEither :: x -> Either x Void


toEither = \x -> Left x

And similarly, we would use the Right constructor if we were trying


to construct an Either Void x. But what about the inverse of this
function? What about the one that goes from Either x Void to x?

fromEither :: Either x Void -> x


fromEither (Left x) = x
fromEither (Right ‽) = ‽

It’s clear that if we receive a Left constructor with an x as its payload


we must simply return that x. But what if we receive a Right? What
do we do with the Void value that comes as its payload? How do we
obtain the x that we must return from that Void value?

Read that again, go on. A Void value? Impossible, there’s no such


thing as a Void value, that’s absurd. And that’s the clever trick. How
would we construct a value of type Either x Void using the Right
constructor if we wanted to do so? Well, we wouldn’t. We just
can’t do it. In that case, the type of the Right constructor would be
Void → Either x Void, which implies that in order to obtain a value
of type Either x Void we first need to provide an impossible value of
type Void, which renders the Right constructor completely
unusable, meaning that a value of type Either x Void can only ever
be Left x. That is, much like how we could determine that an
expression of type Unit must always be the value Unit, a value of
type Either x Void must always be Left x. And, of course, the
opposite is true for Either Void x, where only Right x can exist.

So how do we implement fromEither, then? The answer will


disappoint you.

fromEither :: Either x Void -> x


fromEither (Left x) = x
fromEither (Right _) = undefined

You see, that second equation will never happen, so we can happily
make our function bottom out there, confident that this code will
never be evaluated.

The Void type corresponds to the idea of zero, the identity element
for the addition of types, for Either. And indeed, once we
acknowledge the relevant isomorphisms, we find in sum types a
monoid too.
146. Less is more
What about other common algebraic operations such as subtraction
and division? Well, no luck there. It doesn’t make sense to subtract
types, nor to divide them, so there’s no correspondence between
those operations and our algebraic datatypes.

Think about it. What would Digit minus Bool, allegedly


corresponding to 10 - 2, be? Sure, we could come up with a
completely new type with cardinality eight that doesn’t mention
Digit at all, but this would be just an ad-hoc transformation of the
type Digit, not the result of applying a type-constructor akin to
Either or (,) to both Digit and Bool in order to get a new datatype of
the desired cardinality. No, there’s no direct correspondence
between subtraction and algebraic datatypes. And similarly, there’s
no correspondence with division. Generally speaking, there’s no
correspondence between types and algebraic operations that could
make the cardinalities of our types smaller. Types can only grow,
not shrink. Well, technically, they can always go down to zero if we
pair them with Void.

(Bool, Void)

See? This type has zero inhabitants, for we can never create the
value of type Void we need in order to construct a value of type
(Bool, Void). This corresponds to the idea that multiplying by zero
equals zero. But other than this corner case, types don’t shrink, they
only ever grow, so shrinking operations such as division and
subtraction do not have a correspondence with operation on types.
Having said that, look at this datatype:
data List a = Nil | Cons a (List a)

A List is made out of products, sums and recursion. What can we


do with it? Is there a correspondence between recursion and
algebraic expressions? Let’s see.

Let’s start by writing down the definition of List as an algebraic


equation, pretending that list is the name of a mathematical
function, and translating the right hand side of this definition to
additions and multiplications as we’ve been doing so far.

list(a) = 1 + a × list(a)

Now, this is just an algebraic equation, so as with any other


equation we can move things around preserving the equality,
ideally with a goal in mind. In our case, since we are trying to
determine what list(a) means, we want to move things around so
that list(a) remains on one side of the equation, and on the other
side we have an expression not involving list(a) at all. In algebraic
parlance, we want to solve this equation for list(a). You might have
learned how to do this in high-school, but you may also have
forgotten, so here’s how. Be warned, this is boring.

The basic idea is that if we perform a same operation, any


operation, on both sides of the equation at the same time, the
equality between these sides is maintained. The trick is that
carefully selected operations will cancel out with others that were
previously present in the equation, and things will seem to “move
around”. Let’s try. Let’s subtract a × list(a) from both sides of our
equation.
list(a) - a × list(a) = 1 + a × list(a) - a × list(a)

Now, on the right-hand side of our equation, we are adding a ×


list(a) only to subtract it afterwards, taking us back to where we
were before adding it in the first place, which prompts us to
wonder whether we could perhaps avoid all this trouble if we just
don’t add nor subtract a × list(a) at all. In other words, this
addition and this subtraction cancel each other out. Let’s get rid of
them.

list(a) - a × list(a) = 1

Alright. Also, unrelated, we know that one is the multiplicative


identity, meaning that multiplying by it doesn’t change the value of
our expressions. So, just to make a point, let’s multiply our leftmost
list(a) by one.

1 × list(a) - a × list(a) = 1

On the left side of this equation, list(a) is multiplying both 1 and a


in this subtraction, so we can factor this out as a multiplication of
list(a) by 1 - a. Remember, multiplication distributes over
addition and subtraction, and by factoring out that multiplication
we are “undistributing” it.

list(a) × (1 - a) = 1

Next, we can try to divide both sides of this equation by 1 - a.

(list(a) × (1 - a)) / (1 - a) = 1 / (1 - a)
And finally, seeing how on the left-side, 1 - a appears as part of a
multiplication and a division that cancel each other out, we can just
remove them.

list(a) = 1 / (1 - a)

Great. We arrived somewhere. This is saying that list(a), the


algebraic expression that corresponds to our Haskell datatype List
a, equals the algebraic expression 1 / (1 - a). And now what? How
do we translate that back to Haskell? We only have divisions and
subtractions there, but we know that we have no correspondence
between those operations and Haskell types. What’s going on?
Have we lost once again?

It turns out that an expression like 1 / (1 - a) can be seen through


the eyes of geometry as an infinite geometric series with this shape:

1 / (1 - a) = 1 + a + a² + a³ + …

And so on, infinitely. But look, we only have additions and powers
there, and powers are just multiplications repeated over and over
again.

1 / (1 - a) = 1 + a + a × a + a × a × a + …

This is fine. We know how to translate additions and


multiplications to types:
Either Unit
(Either a
(Either (a, a)
(Either (a, a, a)
… infinitely many more …

In other words, we are saying that a list of as is either Unit, which


corresponds to the empty list, or one a, corresponding to the one-
element list, or a pair of as, corresponding to the two-element lists,
or three as, corresponding to a list with three as in it, and so on,
infinitely. Of course we can’t list infinitely many constructors,
which is why we use recursion to define lists instead. But yes, even
recursive datatypes have corresponding algebraic counterparts.
147. Power
We know how to translate the algebraic expression y³ to types. It’s
just y multiplied by itself, and by itself again, which in types we can
easily express as a product type of three ys such as (y, y, y). But
what about something like yˣ? How do we multiply y by itself x
times? How many times are “x times” anyway? Have we lost?

Not quite. It turns out that algebraic exponentiation corresponds


to function types. In particular, yˣ corresponds to a function x → y
whose cardinality equals the numeric value of yˣ. Let’s look at an
example, 3², which in Haskell corresponds to a function taking as
input a type with cardinality two, such as Bool, and returning as
output a type with cardinality three, such as Maybe Bool.

Bool -> Maybe Bool

What we are claiming is that there are 3² inhabitants of this type.


That is, there are nine different functions we could write that take a
Bool as input and return Maybe Bool as output. And indeed, here
they are, all nine of them implemented as partial applications of the
bool function.
f1, f2, f3, f4, f5, f6, f7, f8, f9
:: Bool -> Maybe Bool
f1 = bool Nothing Nothing
f2 = bool Nothing (Just False)
f3 = bool Nothing (Just True)
f4 = bool (Just False) Nothing
f5 = bool (Just False) (Just False)
f6 = bool (Just False) (Just True)
f7 = bool (Just True) Nothing
f8 = bool (Just True) (Just False)
f9 = bool (Just True) (Just True)

And yes, those first two lines saying f1, …, f9 :: Bool → Maybe Bool
are valid Haskell syntax too. When we have many expressions with
a same type, we can write down their names separated by comas
and assign a type to all of them at the same time using this syntax.

We also claimed before that types with a same cardinality are


isomorphic to each other. Is this still true for functions? Well, let’s
see, let’s try to find an isomorphism with another type having the
same cardinality as Bool → Maybe Bool, which is nine.

data X = X1 | X2 | X3 | X4 | X5 | X6 | X7 | X8 | X9

Sure, X should work. It has nine inhabitants. All we need now is a


bijection between X and Bool → Maybe Bool, as well as its inverse.
Let’s try converting values of type X to values of type Bool → Maybe
Bool first.
fromX :: X -> (Bool -> Maybe Bool)
fromX X1 = f1
fromX X2 = f2
fromX X3 = f3
fromX X4 = f4
fromX X5 = f5
fromX X6 = f6
fromX X7 = f7
fromX X8 = f8
fromX X9 = f9

No surprises here. We simply map every distinct input to a distinct


output function among the ones we defined before, making sure
that the image of fromX equals its codomain, which indeed it does.
But what about the inverse of this function?

toX :: (Bool -> Maybe Bool) -> X

We haven’t quite said it yet, but functions can’t be compared for


equality using (==), nor can they be pattern-matched against —not
in Haskell, anyway— so we can’t really inspect how this function
was defined and decide which X to return based on that. Once a
function exists, all we can do with it is apply it. Alright then, let’s
see if we can solve this by applying it. And yes, applying a function
could be a more computationally intensive process than just
pattern-matching against constructors, so in principle, exploiting
our isomorphism in this direction could be a more demanding
operation for our computer. Nonetheless, computationally
intensive or not, the result would be correct.

How do we do this? We have a function Bool → Maybe Bool, we


know all we can do is apply it, and we know that there are two such
Bools to which we could apply it, True and False. So, to which of
them do we apply it? Well, we are trying to come up with a bijective
function, which among other things implies that the image of this
function and its codomain must be the same. That is, this function
must be surjective. But see what happens if we apply the function
to, say, False.

toX :: (Bool -> Maybe Bool) -> X


toX = \f ->
case f False of
Nothing -> ‽
Just False -> ‽
Just True -> ‽

Even though the cardinality of our codomain X is nine, the


cardinality of our image is just three. For this reason, this is not a
surjective function, let alone a bijective one. And of course,
applying our function to True would lead to the same result, since
we’d still only have three different patterns to match against f True,
leading to the cardinality of toX's image to be just three. No, what
we need to do is apply f to both False and True, making sure we deal
with all the nine possible combinations of their results.
toX :: (Bool -> Maybe Bool) -> X
toX = \f ->
case (f False, f True) of
(Nothing, Nothing) -> X1
(Nothing, Just False) -> X2
(Nothing, Just True) -> X3
(Just False, Nothing) -> X4
(Just False, Just False) -> X5
(Just False, Just True) -> X6
(Just True, Nothing) -> X7
(Just True, Just False) -> X8
(Just True, Just True) -> X9

This is fine. We can apply f as many times as we want. Or in general


any function, not just f. Other than our computer doing arguably
unnecessary work, nothing bad can come out of applying
functions. Anyway, we have restored the surjectivity and bijectivity
of toX, demonstrating at last the existence of an isomorphism
between X and Bool → Maybe Bool, two types with the same
cardinality.

toX . fromX = id

fromX . toX = id

So, yes, functions are isomorphic to other types with the same
cardinality. But of course, functions embody mystery and
computation too, which is why we use them instead of their
isomorphic types. In other words, this exploration about a
function’s isomorphism was mostly a curiosity, and we can forget
all about it now.
148. Ex falso
Wait, wait, wait. Sorry, false alarm. Don’t forget about functions
and exponentiations just yet. There’s actually something else we
should bring our attention to, first. Two things, actually, two
fascinating situations. The first one is x¹, which in algebra equals x,
and in Haskell translates to an isomorphism between Unit → x and
x.

Unit -> x ≈ x

Is this true? Well, let’s see if we can come up with a bijective


function and its inverse. First, let’s go from Unit → x to x.

foo :: (Unit -> x) -> x


foo f = f Unit

That was easy. We have a function that consumes a Unit in order to


produce an x, and we know we can always make a Unit out of thin
air. So we just make one, apply f to it, and return the resulting x.
What about the inverse of foo?

oof :: x -> (Unit -> x)


oof = const

Well, that’s even easier. oof is a function that takes an x, and returns
a function that ignores any Unit it recives and outputs the original x.
We could have pattern matched against Unit, of course, but const,
of type ∀ a b. a → (b → a), works too. Remember, those rightmost
parentheses are redundant. Curious, right?
And what about x⁰, which algebra says equals one, which in Haskell
corresponds to Void → x being isomorphic to Unit?

Void -> x ≈ Unit

Strange, isn’t it? Well, let’s see. Let’s try to implement a bijective
function from Void → x to Unit.

bar :: (Void -> x) -> Unit


bar _ = Unit

That was easy. Values of type Unit can be created out of thin air, so
we just create one and return it, why not? In any case, even if we
wanted, we wouldn’t be able to use that function Void → x because
there’s just no Void to which we could apply it, so all we can do with
that function is ignore it.

bar is clearly a surjective function, since its image matches its


codomain, but is it an injective one? That is, does bar map each
distinct value of type Void → x into a distinct value of type Unit?
Well, yes, because there’s only one such value.

absurd :: Void -> x


absurd = const undefined

Absurd, I know. This function says “give me a Void, and in return


I’ll give you any x you want”. Tempting, right? Except we can never
give absurd a Void, so we have no way of proving that absurd is just
bluffing. This bluff, nevertheless, inhabits Void → x. And it is,
actually, its only inhabitant, seeing how bluffing is all a function
with this type could ever do. So yes, our function bar above is an
injective one. It takes each distinct value of type Void → x, of which
there is just one, absurd, into a different value of type Unit.

What about the inverse of bar, the function that converts Unit into
a function of type Void → x? Well, we know there’s only one such
Unit, and we just learned that there’s only one such Void → x, so the
implementation is rather straightforward, even if absurd.

rab :: Unit -> (Void -> x)


rab Unit = absurd

See? Fascinating. Silly, but fascinating nonetheless.

And now we can finally forget about all this. For real this time.
Poof. The correspondences between algebraic expressions and
types continue, sure, but we will stop here. All we wanted to say,
really, is that the product of types is a monoid with Unit as its
identity element, and we already mentioned it a couple of chapters
ago, before taking our long diversion—a word that in Spanish, by
the way, means fun. So, having said that, we can now get back on
track.
149. Myriad
The reason why the product of types being a monoid matters is this:

composeParsers :: Parser a -> Parser b -> Parser (a, b)

Remember composeParsers? It was the function which took two


Parsers, one for a and one for b, and composed them into a new
Parser that after parsing a and b, in that order, produced both of
them as result in a pair (a, b). Internally, it made sure the leftovers
from parsing a were fed into the b's Parser as input, and that parsing
failures from the individual Parsers were composed too.

And what does composeParsers have to do with monoids? Well,


everything, for composeParsers is a monoid too. Just look at it side by
side with another well-known monoid.

composeParsers :: Parser a -> Parser b -> Parser (a, b)


(,) :: a -> b -> (a, b)

composeParsers behaves just like (,), the product of types, which we


know is a monoid with Unit as its identity element. Well, at least
insofar as the as and the bs are concerned, that is.

Monoids bring understanding. We’ll soon distill Parsers and a


myriad monoids more, allegedly complex beasts, into a very simple
idea. This is the way of the monoid. We’ve seen many of them
already, we just didn’t know they were monoids too.

But composeParsers and (,) are not exactly the same monoid, the
product of types. If we were to pair two Parsers for a and b as a
product type with (,), we’d end up with (Parser a, Parser b), not
Parser (a, b). Of course, we could always create a function that
takes one such (Parser a, Parser b) and returns a Parser (a, b) to
mitigate this fact.

foo :: (Parser a, Parser b) -> Parser (a, b)


foo (pa, pb) = composeParsers pa pb

Wait, what? All this function is doing is taking Parser a and Parser
b out of the tuple, and giving them to composeParsers as separate
inputs. Other than the fact that the input Parsers come inside a
pair, this function does exactly the same as composeParsers. What’s
going on?
150. Spice
Any two functions (x, y) → z and x → y → z are isomorphic to each
other. This has nothing to do with parsers nor monoids, but with
that delicious Indian cuisine.

curry :: ((x, y) -> z) -> (x -> y -> z)


curry f = \x y -> f (x, y)

Actually, it has nothing to do with Indian cuisine. Apologies for


the temptation. But yes, this function is historically called curry.
We wrote down its implementation for completeness, but
parametricity says this is the only possible implementation of this
function, so we could have skipped it.

We say that x → y → z is the curried form of the function (x, y) → z.


And, of course, since we called these two types isomorphic, there
must be an inverse to this function, too.

uncurry :: (x -> y -> z) -> ((x, y) -> z)


uncurry f = \(x, y) -> f x y

Again, a straightforward and unique implementation. We say that


(x, y) → z is the uncurried form of x → y → z. Or we don’t, actually.
Nobody talks like that.

curry . uncurry == id

uncurry . curry == id

Now, the reason why this isomorphism is of particular interest to


us programmers is because it proves that there’s really no difference
between a function taking two input values as separate parameters,
or as just one parameter that happens to be a pair containing those
values. More generally, a function with any number of input
parameters is isomorphic to a function taking just one product type
with that many values as its sole input.

curry
:: ((a, b) -> c)
-> (a -> b -> c)

curry . curry
:: (((a, b), c) -> d)
-> (a -> b -> c -> d)

curry . curry . curry . uncurry . uncurry . uncurry


:: (a -> b -> c -> d -> e)
-> (a -> b -> c -> d -> e)

Well, technically speaking, we know that functions only ever take


one input parameter at most. We have those invisible rightmost
parentheses in our function types, remember?

curry :: ((a, b) -> c) -> (a -> (b -> c))

What’s happening, conceptually at least, is that curry transforms a


function taking two inputs values as a product type into two
functions, each of them taking just one input value individually.

In other words, we’ve accidentally proved that product types are


unnecessary for computation, seeing how we can always take the
values inside a product type as separate input parameters instead.
Are product types convenient? Sure, but they are unnecessary too.
Indeed, we didn’t say anything about pairing back when we were
exploring the lambda calculus, which supposedly can do everything
a computer can using nothing but functions, so there must be some
truth to this. We’ll learn more about this later on, when we build
our own programming language.
151. Government
Alright then, composeParsers is a monoid somehow related to
product types, to (,), but not quite the same thing. What kind of
monoid is it, then? Well, let’s see if we can uncover the truth by just
trying to prove that this is indeed a monoid. As a starting point, we
have a binary operation, composeParsers.

composeParsers :: Parser a -> Parser b -> Parser (a, b)

Is it an associative binary operation? That is, are composeParsers pa


(composeParsers pb pc) and composeParsers (composeParsers pa pb)
pc the same? Well, they are most certainly not equal, because while
one results in a value of type Parser (a, (b, c)), the other one
results in a value of type Parser ((a, b), c). But they are
isomorphic. Both in the fact that the pairs (a, (b, c)) and ((a, b),
c) are isomorphic themselves, and that in both cases pa will
consume its input first, followed by pb, and by pc at last. So, yes,
composeParsers is associative up to isomorphism.

composeParsers pa (composeParsers pb pc)


≈ composeParsers (composeParsers pa pb) pc

We can prove this isomorphism by implementing a bijective


function that simply rearranges the output produced by one of the
Parsers.
parserAssoc :: Parser (a, (b, c)) -> Parser ((a, b), c)
parserAssoc p = Parser (\s0 ->
case runParser p s0 of
Nothing -> Nothing
Just (s1, (a, (b, c))) -> Just (s1, ((a, b), c)))

Proving that composeParsers is associative, however, is not just a


matter of rearranging the pairs that show up as output of this Parser.
If it was just that, then the following nonsense would prove
associativity too:

government :: Parser (a, (b, c)) -> Parser ((a, b), c)


government = const (Parser (const Nothing))

While the type of government suggests it achieves something useful,


the execution of government proves otherwise. government exists by
taking away the accomplishments of the given Parser (a, (b, c))
and replacing them with grand promises that turn out to be
Nothing. Defined in a fascinating manner so as to put readers in awe,
government doesn’t prove associativity at all.

The associativity of composeParser must happen in two places: On


the a, b and c from the Parser's output, of course, but also inside the
Parser, which must compose in a predictable manner, as mandated
by the second half of a monoid, its identity element.
152. Another one
Unit is the identity element for product types. And, seeing how
composeParsers and (,) are so closely related, we’ll probably also
have to involve Unit somehow.

(Unit, a) ≈ a ≈ (a, Unit)

If, once again, we observe how (,) and composeParsers compare,


we’ll find a hint.

composeParsers :: Parser a -> Parser b -> Parser (a, b)


(,) :: a -> b -> (a, b)

composeParsers expects our as and bs to be outputs from these


Parsers, not just standalone values, so we have to take that into
consideration. That is, just like how applying (,) to a value of type
Unit and a value of type a results in a value isomorphic to that
original a, applying composeParsers to a value of type Parser Unit and
a value of type Parser a should result in a value isomorphic to that
original Parser a.

Where do we get a value of type Parser Unit, though? Well, maybe


we can just invent one.

unit :: Parser Unit


unit = Parser (\s -> Just (s, Unit))

Here, unit, all in lowercase letters, is a Parser that doesn’t consume


any input yet it always succeeds to parse a Unit. On the one hand,
this is fine, because we know that Units can be created out of thin
air. But on the other hand, we are departing from the idea that a
Parser is expected to derive “meaning” from an input String. In our
case, unit is ignoring its input String completely, and the Unit it
returns is certainly no “meaning” derived from it.

Is unit a silly idea, then? No, it’s not, and we’ll soon explain why.
But first, let’s just assume it’s right, and while we have unit at hand,
let’s finally state the identity law that composeParsers must satisfy:

composeParsers unit pa ≈ pa

composeParsers pa unit ≈ pa

That is, composing any Parser with unit must result in that same
Parser right away. Of course, we know that if pa has type Parser a,
then composeParsers unit pa, say, will have the different type Parser
(Unit, a). But we are grown ups now, and we understand that
while these two expressions don’t even have the same type, they
could still be isomorphic. There’s hope.

But, is there truth? Hope will accomplish nothing. Not here, not
anywhere. We need truth. Heroes would prove this to be true using
equational reasoning. We, subject to the physical constraints of
these pages, but more importantly, to our love for these words, will
just spell it out. Yes, it is true that these things are isomorphic.

First, because unit doesn’t consume any of its input, making it


available as leftovers to whomever comes next, untouched. unit, in
this regard, is identity. Second, because unit never fails at parsing.
unit, in this regard, is Just. And third, because the output unit
provides, Unit, adds no meaning of its own. unit, in this regard, is
Unit.
unit is the composition of three units, three identities, in one. This
is how we know isomorphisms between Parser a, Parser (Unit, a)
and Parser (a, Unit) exist. Composing something with an identity
has never led to anything but itself.

To contrast, would the following be an identity for our monoid?

not_the_unit :: Parser Unit


not_the_unit = Parser (const Nothing)

No, of course not, it says so in the tin. But if history has taught us
something, it’s that people tend to misunderstand blatantly
obvious things. People will see the type and assume the wrong
thing. So let’s dig deeper. If not_the_unit was our identity element,
our unit, composing it with a Parser a would lead to a Parser (Unit,
a) isomorphic to Parser a. Which, among other things, implies that
the newly composed Parser (Unit, a) would succeed in parsing any
input which the original Parser a would. Alas, it would not, for
whether the original Parser a succeeds or not, not_the_unit would
cause the newly composed Parser (Unit, a) to fail.

To sum up, we now know that composeParsers is the associative


operation of our monoid and we know that unit, all in lowercase, is
its identity element. What we don’t know is how can Unit be a
sensible output from a Parser that is supposed to derive “meaning”
from Strings. Unit means nothing.
153. Alles klar
We have been describing a Parser x as something that given a String
produces something of type x, and we have focused our attention
on the fact that this x is somehow “meaning” that was trapped in
that String. But what if we’ve been paying attention to the wrong
thing?

A Parser produces a value of type x, that’s what fundamentally


matters. And as such, it can produce any x it sees fit, like Unit or the
number 7. That a Parser also happens to be able to derive meaning
from String is tangential. It’s important, sure, that’s the whole
reason why the Parser type even exists. But the importance of a
Parser “parsing” rather than doing something else is less relevant
than we may think. The uniqueness of “what it means to be a
Parser” is comparable to what it means to be a saxophone. Does it
sound different than a piano? Sure it does, but ultimately, they
both sound, and that’s what matters to us programmers. We are
composers. We care about harmony and rhythm, about music as a
whole, not about the individual trumpets, cymbals or guitars. We
care about whether something produces an x or not. How that x
comes to be is irrelevant.

And production is something we learned to associate with positive


argument positions a long time ago. But, more importantly, with
the closely related topic of Functors. Well, it turns out that a Parser,
despite its apparent uniqueness, is mostly just another boring
Functor. And we love boredom, it’s fun. I mean Functors, we love
Functors.

We can prove that a Parser is indeed a Functor by implementing a


Functor instance for it, which boils down to implementing fmap, the
function that covariantly lifts a function of type a → b into a
function of type Parser a → Parser b.

instance Functor Parser where


fmap :: (a -> b) -> (Parser a -> Parser b)
fmap f = \pa -> Parser (\s0 ->
case runParser pa s0 of
Nothing -> Nothing
Just (s1, a) -> Just (s1, f a))

Easy enough. And, by the way, specifying the type of fmap in this
instance, or more generally, of any method in any instance, is
unnecessary. It’s fully determined from the instance head, where we
said that Parser is who we are giving this instance to.

In fmap, we are creating a new Parser b that, when run, will actually
provide its entire input String to the original Parser a, reuse any
leftovers from it as its own, and preserve any parsing failure too.
That is, this new Parser b, insofar as “what it means to be a Parser”,
behaves exactly like the original Parser a did. However, rather than
eventually producing a value of type a, it produces a value of type b
obtained by applying the function a → b to the a produced by
Parser a.

And as if by magic, among other examples, we can now have a


Parser that parses "t" as False and "f" as True by simply fmapping not
over the value of type Bool that results from parseBool.

parseNegatedBool :: Parser Bool


parseNegatedBool = fmap not parseBool

We can try parseNegatedBool in GHCi to verify that it accomplishes


what we expect.

> runParser parseNegatedBool "tfx"


Just ("fx", False)
> runParser parseNegatedBool "x"
Nothing

In the first example, where parseBool would have produced True as


its parsing result, parseNegatedBool produces False instead, the result
of applying not to that original True. We also see how fmapping over
a Parser doesn’t affect its leftover management in any way, for "fx"
is the same leftover String that parseBool would have returned. In
the second example, we can see how parsing failures are preserved
too.

And, of course, like with every other Functor, we must ensure that
the functor laws, which talk about identity and composition, hold.

fmap id == id

fmap (g . f) == fmap g . fmap f

Feel free to grab your pen and paper to prove, using equational
reasoning, that indeed they hold.

Now, knowing that Parser is a Functor, we can do something silly.

regime :: Parser Unit


regime = fmap (const Unit) parseBool

You see, there used to be some truth in the output of parseBool. But
now, silenced by the regime, the truth is gone and the Unit took its
place. Nevertheless, regime still sequesters the relevant String, the
evidence that led to the stolen Bool.

> runParser regime "teverything is fine"


Just ("everything is fine", Unit)
> runParser regime "feverything is fine"
Just ("everything is fine", Unit)

And while the regime manages to be both and at the


same time, it also shows that it is perfectly possible to have a Parser's
output be completely unrelated to the String it consumes.

In Parser x, the Parser and the x have lives of their own. In the
grand scheme of things, it’s only a coincidence that from time to
time the x and the input String are related. fmap is how we deal with
the x output, and functions poking inside the guts of a Parser, like
composeParser, are how we deal with Parsers themselves.

So, the regime does something as a Parser, but as a Unit it’s rather
moot. Can we have the opposite? Can we have a Parser that doesn’t
do anything interesting as a Parser but produces a meaningful
output nonetheless? Sure we can, and the process is almost the
same.

problem :: Parser Bool


problem = fmap (const False) unit

What changes is that we take unit as our starting point, the Parser
that does nothing. All we need to do is use fmap to modify the Unit
value which unit normally produces. In our case, we are replacing it
with False.
> runParser problem "help"
Just ("help", False)

See? No problem. Everything is fine.


154. Mechanical
Before proceeding, let’s explore a different way of defining fmap for
Parser that highlights even more the fact that Functor doesn’t care at
all whether we are parsing a String or sending a rocket to outer
space. Let’s rewrite fmap in a way that doesn’t explicitly pay
attention to the insides of a Parser at all.

fmap :: (a -> b) -> Parser a -> Parser b


fmap f = Parser . fmap (fmap (fmap f)) . runParser

This silly looking definition is quite enlightening, even if cryptic


too. We’ll read it together to understand how, but first let’s remind
ourselves of the definition of the Parser datatype.

data Parser x = Parser (String -> Maybe (String, x))

The type of fmap implies three interesting things in our


implementation. First, that the type of f is a → b. Second, that the
type of the Parser constructor we are ultimately using to construct a
Parser b has type (String → Maybe (String, b)) → Parser b. And
third, that runParser, the function we use to remove the Parser
“wrapper”, has type Parser a → (String → Maybe (String, a)).

In other words, in our allegedly cryptic point-free definition, in


between the applications of runParser and Parser, we are converting
a function of type String → Maybe (String, a)) into a function of
type String → Maybe (String, b)), where all that’s supposed to
change is the a into a b. So, how do we do that?

We start by noticing that the a is inside a tuple, a pair. And pairs, we


know, are Functors too. More precisely, in our case, (,) String is a
Functor, meaning that fmapping a function a → b over a pair (String,
a) will lead to a pair (String, b), which is exactly what we need.
However, this pair is trapped inside a Maybe (String, a), meaning
that perhaps there’s no pair at all. That is, we would only be able to
apply fmap f over the tuple when the Maybe happens to be
constructed with Just.

Luckily for us, Maybe is a Functor too, meaning that using fmap we
could lift fmap f, our function of type (String, a) → (String, b),
into a function of type Maybe (String, a) → Maybe (String, b) which
would apply said fmap f only when the Maybe is a Just containing a
(String, a).

But we are not done yet, because in between runParser and Parser
we are transforming a function of type String → Maybe (String, a),
not just a Maybe (String, a). That is, what we are actually trying to
modify is the output of a function. Well, this is what function
composition is for, isn’t it? And function composition goes by
many names, one of them being fmap. In other words, using fmap
once again, we could lift our function fmap (fmap f) of type Maybe
(String, a) → Maybe (String, b) into a function of type (String →
Maybe (String, a)) → (String → Maybe (String, b)), which is exactly
what we need.

So, much like unit was the composition of three different identity-
like things, the Functor instance for Parser is just the composition of
three other Functors, of three fmaps.

If we ask GHCi what the type of said composition is, the answer is
rather beautiful.
fmap . fmap . fmap
:: (Functor f, Functor g, Functor h)
=> (a -> b)
-> f (g (h a))
-> f (g (h b))

All f, g and h are Functors. If we pick f to be (→) String, g to be Maybe,


and h to be (,) String, then we end up with this:

fmap . fmap . fmap


:: (a -> b)
-> (->) String (Maybe ((,) String a))
-> (->) String (Maybe ((,) String b))

Which looks horrible in prefix notation, but if we rearrange it to its


infix form, we see this is exactly what we were looking for.

fmap . fmap . fmap


:: (a -> b)
-> (String -> Maybe (String, a))
-> (String -> Maybe (String, b))

And we know that String → Maybe (String, x) is just a different type


for what we called Parser x, so all that remains is to take care of the
arguably superfluous Parser wrapper, which is what the
applications of runParser and Parser accomplish.

So, you see, it doesn’t really matter what our Parser does. Our
implementation of its Functor instance, which deliberately ignored
inputs, leftovers and failure altogether, proves that.
155. Poke
What’s important, now, is that Parser is a Functor, which means we
can peek and poke its output any way we see fit without taking its
guts apart each time, without even mentioning we are dealing with
a Parser at all. For example, if we imagine a function foo of type Bool
→ String, then fmap foo would have this type:

fmap foo :: Functor f => f Bool -> f String

fmap foo is the function that given a Functor f producing values of


type Bool, returns that same f, but this time producing values of
type String rather than Bool. Any Functor, including Parser.

> :t fmap foo (Just True)


:: Maybe String

> :t fmap foo [True, False]


:: [String]

> :t fmap foo id


:: Bool -> String

> :t fmap foo parseBool


:: Parser String

The cases where we fmap foo over the function id and parseBool are
particularly interesting because they are modifying the output of the
function and the Parser, respectively, even if no input has been
received by then yet. Which, depending on where you are coming
from, could be unsurprising and expected, or completely shocking.
156. Beauté
So, like many other beautiful things in life, Parser is a Functor. And
while it doesn’t really fit the Monoid typeclass, Parser is a beautiful
monoid too. But moreover, seeing as this convergence of beauty is
unlikely to be an isolated event, we give the situation a name,
somewhat hoping we have more of them. We call a monoid known
to be a Functor, a Functor known to be a monoid, a monoidal
functor. And this name has a home, too.

class (Functor f) => Monoidal f where


unit :: f Unit
pair :: f a -> f b -> f (a, b)

Intuitively, pair takes two separate values a and b, both wrapped in


the same f, and returns one value (a, b) still wrapped in that f.
That’s pretty much all the intuition we’ll need in practice. Read
this again, go on. We take two things and turn them into one.

The Monoidal typeclass says two things. First, as every other


typeclass, it says that reasonable definitions of unit and pair exist for
types f for which there is a Monoidal instance. Parser is one such f,
with unit just as we defined it before, and pair being just a different
name for what so far we’ve been calling composeParser. Let’s give the
full definition of the Monoidal instance for Parser.
instance Monoidal Parser where
unit :: Parser Unit
unit = Parser (\s -> Just (s, Unit))

pair :: Parser a -> Parser b -> Parser (a, b)


pair pa pb = Parser (\s0 ->
case runParser pa s0 of
Nothing -> Nothing
Just (s1, a) ->
case runParser pb s1 of
Nothing -> Nothing
Just (s2, b) -> Just (s2, (a, b)))

But the Monoidal typeclass also says something else, using a new
syntax that we haven’t seen before. Monoidal f says that f must be a
Functor too.

class (Functor f) => Monoidal f …

If we try to implement a Monoidal instance for some type f that is


not a Functor, then type-checking will fail. We say that Functor is a
superclass of the Monoidal typeclass, constraining the Monoidal
instances that can exist.

Generally speaking, a typeclass X can have one or more superclasses


A, B, etc., specified in the following way:

class (A, B, …) => X … where …

But this doesn’t just mean that A and B are constraints that need to
be satisfied in order for some instance of X to exists. It also means
that whenever X itself is satisfied, then A and B are satisfied too. We
can observe this useful feature with a small GHCi example:

> :t fmap id unit


fmap id unit :: Monoidal f => f Unit

When we ask GHCi about the type of the expression fmap id unit,
it says its type is Monoidal f ⇒ f Unit, even though we are clearly
using both unit from the Monoidal typeclass, and fmap from the
Functor typeclass. If satisfying a constraint like Monoidal f didn’t
imply that the superclasses of Monoidal f are satisfied too, then the
type of fmap id unit would need to mention both Monoidal f and
Functor f as their constraints.

fmap id unit :: (Monoidal f, Functor f) => f Unit

But this is kind of silly. It is correct, sure, but saying Functor f


doesn’t really add any new meaning to Monoidal f, does it?
Generally speaking, a typeclass constraint being satisfied implies
that all of the superclasses of that typeclass are satisfied too.

And, by the way, if while learning this you are reminded of logical
implication but baffled at the fat arrow ⇒ going in the opposite
direction, then you are right: It goes in the opposite direction.

Finally, as with any other sensible typeclass worth talking about, we


have laws that any instances of this typeclass must abide by. First,
we have a law requiring that pair be an associative function. Up to
isomorphism, of course.

pair a (pair b c) ≈ pair (pair a b) c


Second, we have a law requiring that unit behaves as the identity
element for pair.

pair unit a ≈ a ≈ pair a unit

Technically, this law can be split into two. There is a left identity
law where Unit appears on the left.

pair unit a ≈ a

And a right identity law where Unit appears on the right.

pair a unit ≈ a

We don’t care much about that difference for the time being.
Anyway, these are essentially the monoid laws. Nothing new for us
here. There is, however, an additional law.

pair (fmap f ma) (fmap g mb) == bimap f g (pair ma mb)

This law, called the naturality law, says that fmapping f and g
separately over two monoidal functors ma and mb before pairing
them, must be equal to fmapping f and g together over pair ma mb,
something we can easily accomplish using bimap. Luckily, we don’t
really need to think about this law. Thanks to parametricity, it will
always be automatically satisfied by all Monoidal instances.
157. So what?
Parser is a monoidal functor. So what? What can we do with this
knowledge that we couldn’t do before? Technically speaking,
nothing. We already knew that Parsers could be composed in this
way, we just didn’t know why. But we must acknowledge that we
only arrived to that composition by chance, after many failed
attempts. We could have avoided that pain and gone straight to the
right answer had we known what to ask for. Well, now we know. Is
it too late? No, not at all.

Parser is just one among many monoidal functors, so all the pain
we went through to understand the composition of Parsers was not
in vain, for we shall be able reuse this knowledge with any other
monoidal functor. That we couldn’t readily recognize the structure
in what we believed to be unique didn’t make those structures any
less true. Going forward, it’ll be our loss if we don’t try to identify
them as soon as possible.

The basic question we should ask ourselves, as soon as we recognize


something as Functor, is whether it makes sense to combine any two
such Functorial values into one. If it does, then chances are we have a
monoidal functor, which will allow us to reason about this
combination, this composition, in a predictable way.

Let’s take another Functor, then, to see how this works. Let’s take
Maybe. Do we think it makes sense to try and combine a value of
type Maybe a with a value of type Maybe b, into a value of type Maybe
(a, b)? Maybe.

pair :: Maybe a -> Maybe b -> Maybe (a, b)


Maybe x conveys the idea of a value of type x maybe being there,
maybe not. pairing two such values, presumably, could convey the
idea of both those values maybe being there, maybe not.

pair :: Maybe a -> Maybe b -> Maybe (a, b)


pair Nothing _ = Nothing
pair _ Nothing = Nothing
pair (Just a) (Just b) = Just (a, b)

Naturally, if any of the input Maybes is Nothing, there’d be no “both a


and b” we could pair, so we simply return Nothing in those
situations. Otherwise, if we have both Just a and Just b, then we
can have Just (a, b) too. Is pair associative? Certainly. Up to
isomorphism, of course. You can prove it yourself if you are bored,
you know how.

What about unit, the value of type Maybe Unit which, when paired
with a Maybe x, results in a value isomorphic to that Maybe x? Well,
considering there are only two inhabitants of this type, we can try
both of them and see what happens. If said Maybe Unit was Nothing,
then pairing it with anything would lead to Nothing as result, which
is fine whenever our Maybe x is Nothing, but terribly wrong
otherwise. It ain’t Nothing, no. It must be the other inhabitant then,
Just Unit. And indeed, if we pair Just Unit with Just x, the
resulting Just (Unit, x) would be isomorphic to Just x. Or the
other way around if we switch the order of the input parameters to
pair. And what if the Maybe unit was Nothing? Well, we get Nothing as
output, which is exactly the same we put in. So, yes, Just Unit is our
unit.
unit :: Maybe Unit
unit = Just Unit

Of course, pair and unit should actually be defined inside the


Monoidal instance for Maybe, but we know that already.

instance Monoidal Maybe where


unit = …
pair = …

Alright, Maybe is a monoidal functor. We didn’t ask for this, but we


got it nonetheless. Why is this useful? Well, it’s not hard to come
up with a toy example that justifies the need for this. In fact, we can
reuse that cooking example from before, where we wanted to be
sure we had both utensils and ingredients before we could cook.

utensils :: Maybe Utensils

ingredients :: Maybe Ingredients

cooking_stuff :: Maybe (Utensils, Ingredients)


cooking_stuff = pair utensils ingredients

And even if we haven’t really focused our attention on it, just like
in the case of Boolean conjunction using (&&), the laziness in our
definition of pair will make sure we don’t go looking for
ingredients until after we’ve made sure we have Utensils nearby.
Laziness is one of those things most easily noticed when ripped
away from us. Cherish it, it’ll prove terribly useful as we advance.
We’d be at a disadvantage without it.
We’ll probably need drinks for dinner too.

drinks :: Maybe Drinks

everything :: Maybe ((Utensils, Ingredients), Drinks)


everything = pair cooking_stuff drinks

And so on, and so on. We can keep on pairing like that for as long
as we want. What have we achieved? Well, how many times have we
checked so far whether we had the things we wanted or not? Zero.
How many times we would need to check if we wanted to start our
dinner? One, we’d just have to check if everyting is Just or Nothing,
even though there are three things that could potentially be missing.
That’s something.

So, you see, Parser and Maybe accomplish two completely different
things. One parses Strings and the other helps us organize dinners.
Yet, we can reason about both of them in the same Monoidal way.
Haskell embraces diversity. Types can be whatever they want to be
in order to achieve whatever they need to achieve. They can pick
their own names, they can pick their own identities. And despite
said beautiful uniqueness, through well understood structures like
the Functor, the Monoid or the Whatnotoid, they can belong. They’ll
share, they’ll compose, they’ll have a clear and loud voice in the
conversation.
158. Fan
Let’s tackle our next Monoidal functor, but this time let’s do
something different. Let’s not think about what pairing these
things even means. Let’s just do it. Let’s ride the parametric
polymorphism and see where it takes us.

instance Monoidal ((->) x) where

That’s right, (→) x shall be our Functor today. That is, the function
that takes x as input. Where, of course, x is a universally quantified
type-variable that could be any Type we want.

Right, just like functions and values universally quantify type


variables automatically unless we ask for something different,
instance definitions do so too. In reality, this is what’s happening
behind the scenes:

instance ∀ (x :: Type). Monoidal ((->) x) where

We don’t usually write the explicit quantification, but there’s


nothing wrong in doing so. In fact, since it makes things more
explicit, some may argue it’s better.

Anyway, (→) x is our chosen Functor, our chosen type-constructor,


so these are the types that Haskell will mandate for the methods in
our Monoidal instance:

unit :: (->) x Unit

pair :: (->) x a -> (->) x b -> (->) x (a, b)


They look horrible written in this prefix form, of course, but if we
rearrange them a bit to their infix form, we’ll see things more
clearly.

unit :: x -> Unit

pair :: (x -> a) -> (x -> b) -> (x -> (a, b))

What do you see? It doesn’t matter. We said we’d chase


parametricity, so that’s what we’ll do. Let’s leave the sightseeing for
later.

unit :: x -> Unit


unit = \_ -> Unit

This is the only implementation unit can have. Is it a bit silly? Sure.
Nonetheless, it’s the only behavior that makes sense. If unit must
return a Unit, then it will be forced to ignore any value it is given as
input. What about pair?

pair :: (x -> a) -> (x -> b) -> (x -> (a, b))


pair f g = \x -> (f x, g x)

Again, the parametric polymorphism in this type forces pair to do


this. There’s nothing else it could do that would type-check. pair
takes two x-consuming functions f and g, and returns a new x
-consuming function that returns, in a tuple, the outputs from
applying both f and g to that x.

What is this good for? Well, imagine we have two functions that we
want to apply to a same input:
double :: Natural -> Natural
double = \x -> x * 2

triple :: Natural -> Natural


triple = \x -> x * 3

We can pair them into a single function that, given a Natural


number, returns both the double and the triple of that number at
the same time.

double_and_triple :: Natural -> (Natural, Natural)


double_and_triple = pair double triple

In this case the types of our inputs and outputs are the same, but
that’s just a coincidence. We could as well have paired a function
Natural → Bool with a function Natural → String to obtain a
function of type Natural → (Bool, String), and it would have been
fine. Anyway, let’s try our function in GHCi.

> double_and_triple 5
(10, 15)

Great, it works. And, of course, we can pair this further with any
other function that takes a Natural as input. Like even, say, the
function that takes a Natural number and returns True if the
number is even, or False otherwise.

> pair double_and_triple even 5


((10, 15), False)
> pair even (pair triple double) 2
(True, (6, 4))
Is unit the appropriate identity element for our associative binary
operation pair? Well, it better be, because there’s no way we can
implement unit differently.

> double 5
10
> pair unit double 5
(Unit, 10)
> pair double unit 5
(10, Unit)

All isomorphic results. Great.

We took a well understood idea, that of monoidal functors, and


tried to see if our thing, the function, fit that idea. And it did,
which led to an “accidental” discovery of a terribly useful new way
of composing functions, one we hadn’t even thought about before.
Isn’t this beautiful? Hadn’t we tried this, chances are we’d be
forever stuck applying a myriad different functions to the same
input values time and time again.

Structures are here. It’s our loss if we refuse to see them.

This way of composing functions also goes by the name of fan-out,


reminding us of how when a single input hits the fan, it spreads all
over the place. And this is such a common way of composing
functions that Haskell dedicates an infix operator to it.

(&&&) :: (x -> a) -> (x -> b) -> (x -> (a, b))


(&&&) = pair

Actually, the type of this function is a bit more general than this
because it’s designed to work with function-like things, rather than
just functions. Remember Profunctor? Anyway, we’ll pretend it
only works with functions for the time being.

> (double &&& triple) 10


(20, 30)
> (double &&& triple &&& quadruple) 10
(20, (30, 40))

We can see how (&&&) associates to the right. This doesn’t mean
much, however, considering how (&&&) must be an associative
function as mandated by the way of the monoid. It could have
associated to the left and the result would have been the same. Up
to isomorphism, that is.
159. Choice
Another Functor, Either x. Let’s see if this one is Monoidal too.

instance Monoidal (Either x) where


unit :: Either x Unit
pair :: Either x a -> Either x b -> Either x (a, b)

We’ll see the implementations of pair and unit soon, but first, let’s
highlight something. Notice how x, the type of the eventual
payload of a Left constructor, if any, is fixed to be x everywhere.
This is not unlike the x in (→) x, which was fixed to be x everywhere
too.

pair :: (x -> a) -> (x -> b) -> (x -> (a, b))

However, unlike that situation, where pair f g created a new


function that consumed an x which it could then provide to both f
and g, here, if pair needs to produce a Left x for some reason, then
that x will need to come from one of the input Eithers. From which
one, though? Both of them could have an x in them.

pair :: Either x a -> Either x b -> Either x (a, b)

This situation can be understood by simply remembering that


while Either x y is covariant in x, x → y is contravariant in it.
Meaning that, quite often, what works for Either doesn’t work for
(→) and vice-versa.

So, what? Isn’t Either x a Monoidal functor after all? Well, actually, it
can be, but in order to be one it must make a choice.
pair :: Either x a -> Either x b -> Either x (a, b)
pair (Right a) (Right b) = Right (a, b)
pair (Left x) _ = Left x
pair _ (Left x) = Left x

Obviously, just like we saw in the Monoidal instance for Maybe, we


can only construct a pair (a, b) if both a and b are present at all.
That is, if both our inputs values have been constructed using
Right. There’s no choice to be made there, it’s trivial.

pair makes a choice when it decides what to do when both its


inputs happen to be Lefties, a situation dealt with by the second
equation above. pair chooses that it will be the payload from the
leftmost Left the one that will be reproduced in the resulting Either
x (a, b). The leftmost, not the rightmost. This is a choice. By
swapping the order of the last two equations, we could have chosen
to perpetuate the rightmost Left payload instead. However, seeing
as we expect things to be evaluated from left to right as they appear
in our code, returning the leftmost Left we encounter, arguably,
makes the most sense.

However, that’s not the entire truth. Later on we’ll learn there are
stronger forces at play here mandating that this be the case. The
leftmost Left shall always be prioritized. So, in reality, there’s was
no choice to be made here. Sorry, false alarm. The take-away from
this experience is that when we don’t know the whole truth, we
may be tempted to make uninformed choices that could be, in fact,
wrong. This is what dangerous humans do. Please, don’t do that.
Being aware of one’s lack of understanding is good. We ask
ourselves not how we are right, but how we are wrong. Faith and
mysticism won’t take us anywhere.
And what about unit? Right, we almost forgot. Well, there’s not
much we can say about it that we haven’t said about the unit for
Maybe.

unit :: Either x Unit


unit = Right Unit

Only Right Unit can behave as the identity element in our Monoidal
instance for Either, for exactly the same reasons that only Just Unit
could behave as one in Maybe's. Similar beasts, Either and Maybe. So
similar, actually, that we’ll frequently benefit from these two fully
parametric functions, hush and note, able to convert between them.

hush :: Either x a -> Maybe a

note :: x -> Maybe a -> Either x a


160. Why not
Anyway, what does the Either monoidal functor mean?

head :: [a] -> Maybe a


head (a:_) = Just a
head _ = Nothing

head only ever “fails” when the input list is empty, and it
communicates this failure by returning Nothing. In other words, we
embraced the type-constructor Maybe to communicate the
possibility failure.

But what if we had a function that could fail for more than one
reason? In that case, Nothing wouldn’t be enough anymore. Let’s go
back to cooking.

utensils :: Maybe Utensils

ingredients :: Maybe Ingredients

These values, despite their bad names misplacing expectations,


perfectly convey the presence or absence of Utensils or Ingredients
individually. However, once we pair them, some of that clarity is
lost.

pair utensils ingredients


:: Maybe (Utensils, Ingredients)

This pairing still perfectly conveys the idea of both the Utensils and
the Ingredients being there or not. However, if either one or both
of them are missing, all we get as result is Nothing, without any
knowledge of who’s to blame for our failed attempt at cooking.
Using Either, however, we can achieve a bit more.

data WhyNot = NoUtensils | NoIngredients

If as result of our pairing we had Either WhyNot (Utensils,


Ingredients) rather than Maybe (Utensils, Ingredients), then
whenever our pairing didn’t result in a Righteous pair of Utensils
and Ingredients, we would be able to peek at the WhyNot value on the
Left to understand why not.

pair (note NoUtensils utensils)


(note NoIngredients ingredients)
:: Either WhyNot (Utensils, Ingredients)

Using note, the function that enriches a value of type Maybe y by


converting it to a value of type Either x y, we modify both utensils
and ingredients so that if they turn out to be Nothing, we convert
them to a Left with a value of type WhyNot explaining what went
wrong.

And notice that while it makes sense to use WhyNot in this pairing, it
wouldn’t make much sense to use it in a standalone utensils, say.

utensils :: Either WhyNot Utensils


utensils = Left NoIngredients

We have defined utensils to report the absence of ingredients,


something which doesn’t make sense at all. Generally speaking, we
should make our errors as precise and useful to our audience as
possible, so that nonsense like this doesn’t happen. Otherwise, the
burden of understanding what utensils really meant passes on to
whomever needs to use these Utensils.

case utensils of
Right u -> … We have some utensils. Nice. …
Left NoUtensils -> … Too bad. We have no utensils. …
Left NoIngredients -> … What is this nonsense? …

We make our errors as small and precise as it reasonably makes


sense, and we let our callers grow them as they see fit, for example,
by using note. The bigger our errors are, the smaller the meaning
they convey.

Anyway, back to our pairing of noted Maybes. If there are no


utensils, we get Left NoUtensils as result. If there are no ingredients,
we get Left NoIngredients. And if there are neither utensils nor
ingredients, we get Left NoUtensils as result. Unsurprisingly, I hope.

pairing two Eithers , we learned before, leans to the leftmost Left in


case two Lefts are provided as input. So, if ultimately we are trying
to evaluate pair (Left NoUtensils) (Left NoIngredients), the result
will be Left NoUtensils. Well, actually, pair won’t even check
whether its second input argument is Left or Right at all. It’ll just
return the leftmost Left as soon as it encounters it. On the one hand
this is great, because we evaluate nothing beyond the leftmost Left,
preserving laziness. But on the other hand, it could be handy to
know whether both the Utensils and the Ingredients are missing.

Well, we can’t have a cake and eat it too. We either look at both
Eithers in order to judge their contents, accumulating the error
reports from all the Lefts we discover, or we bail out as soon as we
encounter the first Left, without having to evaluate any other
Eithers beside it. With Either, we only get the latter behavior.
However, we could have a different Monoidal functor that did
something else, why not? However, this alternative behavior will
have to wait. First, we need to address some parsing issues.
161. Não tem fim
The composition of Parsers shares an unfortunate trait with the
composition of Maybes, where Nothing becomes the result whenever a
Nothing is among the Maybes we attempt to pair, yet we can’t tell
which of the Maybes in question is the Nothing leading to this result.
When pairing Parsers, if one of them fails, we are not able to
identify which one either.

> :t pair parseBool parseDigit


:: Parser (Bool, Digit)
> runParser (pair parseBool parseDigit) someString
Nothing

Why did the Parser fail? We’ll never know unless we manually
inspect someString and try to deduce it ourselves, something
completely unmanageable when rather than two Parsers we find
ourselves composing hundreds of them. Remember, as soon as we
can compose two things, we can compose infinitely many of them.
Composition não tem fim.

So, how do we solve this? Well, we know how. Rather than using
Maybe for conveying failure, we need to use Either. We need to
change the definition of our Parser datatype.

data Parser x = Parser


(String -> Either String (String, x))

We’ve chosen to put a String on the Left side of our Either. The
idea is that a Parser can now cry something interesting like Left
"Expected 't' or 'f'" as it fails, rather than just saying Nothing.
parseBool :: Parser Bool
parseBool = Parser (\s0 -> case s0 of
't':s1 -> Right (s1, True)
'f':s1 -> Right (s1, False)
_ -> Left "Expected 't' or 'f'")

But a lonely Parser is terribly uninteresting. We better modify the


Functor and Monoidal instances, taking the new changes into
account, so that our Parser can make friends.

fmap :: (a -> b) -> Parser a -> Parser b


fmap f = Parser . fmap (fmap (fmap f)) . runParser

Wait, this fmap has exactly the same implementation as before. Why
yes, both Either String and Maybe are Functors, so we don’t really
need to change anything here. The fmap that was lifting a function
(String, a) → (String, b) into Maybe (String, a) → Maybe (String,
b) before is now lifting it to Either String (String, a) → Either
String (String, b), but other than that nothing changes. What
about pair?

pair :: Parser a -> Parser b -> Parser (a, b)


pair pa pb = Parser (\s0 ->
case runParser pa s0 of
Left e -> Left e
Right (s1, a) ->
case runParser pb s1 of
Left e -> Left e
Right (s2, b) -> Right (s2, (a, b)))

Compared to our previous implementation, all that changed is that


rather than dealing with Nothings and Justs, we deal with Lefts and
Rights everywhere. Now, assuming we added a proper error message
to parseDigit too, our previous example would lead to a much
better experience.

> runParser (pair parseBool parseDigit) "x3"


Left "Expected 't' or 'f'"
> runParser (pair parseBool parseDigit) "tx"
Left "Expected a digit '0'..'9'"
> runParser (pair parseBool parseDigit) "t3"
Right ("", (True, D3))

Obviously, we changed the type of runParser too.

Writing beautiful and informative error messages is a delicate


matter. We’ll get better at it as we move forward.
162. Location
In a sense, picking String as our error type goes against our previous
recommendation that the type we chose to convey errors should be
as small and precise as possible. However, we need to take the
context where this error exists into consideration. Small and precise
error messages mainly make sense if they can help a program trying
to recover from that error automatically.

utensils :: Maybe Utensils


utensils = case our_utensils of
Just x -> Just x
Nothing -> neighbour's_utensils

In this example, if we have our own Utensils available, we’ll go


ahead and use them. But if we don’t, we’ll ask some neighbour for
their Utensils, if any. We are, in other words, recovering from failing
to have our own utensils, a very precise situation, by having the
computer automatically do something else for us.

But if we consider the use case for Parsers, which could fail parsing
for a myriad different reasons, none of them which we expect to
automatically recover from, then a String makes a bit more sense.
The errors reported by our Parsers are exclusively intended for
human consumption, not for computers. How would a program
automatically recover from an error saying that a particular
character in our input is not a digit? Would the program just go
and replace the character in question with a digit? Which digit?
That doesn’t make much sense. What if the input was right,
actually, and it was the Parser who was expecting the wrong thing?

If a parsing error happens, any error, it’s either because the input is
malformed or because the Parser is wrong, and fixing any of those
situations requires human intervention. So the best we can do,
really, is to try and be precise about where the parsing error
happened. Even more so if we consider that the number of Chars in
our input String could very well be in the millions. Why not?

Location. All we care about this time is location. We are not


interested in designing our errors so that they can be mechanically
analyzed, but rather, so that they convey useful information about
where parsing failed, and what the Parser was trying to accomplish
there.

> runParser (pair parseBool parseBool) someString


Left "Expected 't' or 'f'"

Without looking inside someString, can we tell which of the two


parseBool failed to parse its input? Of course we can’t. Any of them
could have failed, and since both of them generate exactly the same
error report, we can’t really tell their failures appart. In a sense, we
recreated the uninformative Nothing from before. How do we fix
that?

Well, how do we want to fix it? There are at least two obvious
solutions. One of them could say at which absolute character
position in the input String we encountered the error. Say, at
character position 0, 3 or 43028. This solution manages to be both
very precise and very uninformative at the same time. Alternatively,
we could say something along the lines “failed to parse the user’s
birthdate month number”, which gives a higher level overview of
what the Parser was trying to accomplish when it failed, without
telling us exactly where the crime happened. Luckily, we don’t have
to chose between these alternatives. They complement each other,
and we can have them both.

We’ll tackle this in the same way we tackle every other problem.
We’ll correctly solve the individual small problems we identified,
and then we’ll just compose these correct solutions into a bigger
and still correct solution. Correctness composes.
163. Relative
Let’s tackle the matter of the absolute position of a problematic
Char in the input String first. The idea is that, when a Parser fails, we
want to see both an error message and an absolute character
position indicating where the parsing failed.

> runParser (pair parseBool parseBool) "xy"


Left (0, "Expected 't' or 'f'")
> runParser (pair parseBool parseBool) "ty"
Left (1, "Expected 't' or 'f'")

In the first example above, it’s the leftmost parseBool in the pair the
one that first fails to parse the input "xy". And seeing as 'x' is the
Char that’s causing the whole thing to fail, and how said 'x' appears
as the very first Char in the input String, then we report the Natural
number 0 as the absolute position of the first conflicting Char in the
input String. Remember, we always start counting from zero, not
from one.

In the second example, the first parseBool in the pair successfully


parses its input, but the second one fails. Accordingly, the output
from our use of runParser reports that the Char at position 1 was the
conflicting one. That is, the second Char, the 'y'.

Alright, let’s do this. First, types. We are counting things starting


from zero, so we’ll probably need a Natural number somewhere. In
fact, we already know we want one of those as part of runParser's
output, so maybe let’s start by changing that type.
runParser
:: Parser x
-> String
-> Either (Natural, String) (String, x)

Great. We are saying that if parsing fails, as communicated by a Left


result carrying a (Natural, String) payload, then said Natural shall
tell us at which absolute position in the input String parsing failed,
and next to this Natural we get a Stringy error message too,
describing what went wrong. The Right hand side of the Either is as
before. In order to implement this new runParser, however, we’ll
need to massage our Parser type a bit.

data Parser x = Parser


(String -> Either (Natural, String) (String, x))

Well, well, well… Things are getting a bit insane, aren’t they? That’s
fine. Ours is an excercise in taming complexity, and we are
deliberately trying to show how the solution to these so-called
complex problems boils down to finding the right types and getting
their composition right.

This new type, just like the runParser function, says that if our
parsing function is going to fail, then it better provides information
about where the failure happened. The rest is the same as before.
Let’s rewrite parseBool to take this into account.
parseBool :: Parser Bool
parseBool = Parser (\s0 -> case s0 of
't':s1 -> Right (s1, True)
'f':s1 -> Right (s1, False)
_ -> Left (0, "Expected 't' or 'f'"))

Since parseBool only ever deals with the first Char of its input String,
it will always report 0 as the failing position when it receives some
unexpected input. Of course, we could easily imagine a different
Parser that took more than the first Char of the input String into
consideration. For example, a Parser expecting the String "blue" as
input but getting the String "bland" instead, could report 2 as the
position of the first unexpected Char, "a".

Anyway, seeing as we changed the type of Parser, we’ll need to


modify pair in its Monoidal instance so as to take this new type into
account.

pair :: Parser a -> Parser b -> Parser (a, b)


pair pa pb = Parser (\s0 ->
case runParser pa s0 of
Left (n, e) -> Left (n, e)
Right (s1, a) ->
case runParser pb s1 of
Left (n, e) -> Left (n, e)
Right (s2, b) -> Right (s2, (a, b)))

The Functor instance stays the same as before because all we did was
change the payload on the Left, which fmap completely ignores.
Let’s see if this works, then.
> runParser (pair parseBool parseBool) "xy"
Left (0, "Expected 't' or 'f'")
> runParser (pair parseBool parseBool) "ty"
Left (0, "Expected 't' or 'f'")

What? This ain’t right. The 0 reported in the first example is fine,
yes, because the Char at position 0 in the input String "xy" is
certainly wrong. But in the second example, the error also reports 0
as the failing position, even if we know that this time the Char at
position 1, the 'y', is the culprit. What’s going on? Well, not
composition, that’s for sure.
164. Absolute
The problem we are seeing is that when individual Parsers such as
parseBool fail, they report the relative position where they fail with
respect to their own input, not with respect to the entire input that
was initially provided to runParser by us, in GHCi. That is, these
errors do not report the absolute position of the conflicting Chars in
the input String.

This makes sense, however. How would parseBool know where it is


being executed in this initial input String? In pair pa pb, that
second parser pb doesn’t know how much input pa consumed
before pb's time to parse, so there’s no way it can calculate an
absolute position that takes that into account. Should it, though?
Should pb know about pa's diet? No, it should not. It could, but that
would put an additional burden on pb, who’d now need to worry
about other Parser's affairs too. No, that won’t work. There is,
however, somebody who is already worrying about both pa and pb,
so perhaps we can address this matter there. Namely, in pair.

If pair knew how much input pa consumed in order to successfully


produce its output, then it would be able to add that amount to
the conflicting Char position reported by pb, resulting in a new
position that takes both pa's and pb's affairs into account, without
imposing any burden on neither pa nor pb.

Well, almost no burden. We do need to change our Parser datatype


so that successful executions of our parsing function return how
much input they consumed. pair will need to take this number into
account. But, quite frankly, this is a very nice feature that sooner or
later we would have needed anyway. Of course we will appreciate
knowing how much input was consumed in order to produce a
successful result, perhaps even more so than how much of it was
consumed in order to produce a failure. Let’s change our Parser
datatype to accommodate this.

data Parser x = Parser


(String -> Either (Natural, String)
(Natural, String, x))

Now, our Either type reports on both sides, as a Natural value, a


number indicating how many Chars were successfully consumed by
the parsing function in order to produce the result it did, be it Left
or Right. For example, this is what parseBool would look like now.

parseBool :: Parser Bool


parseBool = Parser (\s0 -> case s0 of
't':s1 -> Right (1, s1, True)
'f':s1 -> Right (1, s1, False)
_ -> Left (0, "Expected 't' or 'f'"))

Indeed, the Righteous scenarios now report how much input they
consumed. The Left situation is the same as before. In any case, all
of these scenarios still talk about the relative positions of the Chars
they consume as they appear in the input String this Parser receives.
parseBool still doesn’t care about how much input other Parsers
consume.

Notice that, seeing as both the Left and the Right must produce a
Natural number now, conveying essentially the same meaning in
both cases, we could have chosen to abstract that common Natural
away in an isomorphic product type like (Natural, Either String
(String, x)). This is not unlike algebra, where a × b + a × c equals
a × (b + c). We’ll encounter this situation time and time again in
our travels. Anyway, we picked a representation already, so let’s stay
with it.

The real magic happens inside pair.

pair :: Parser a -> Parser b -> Parser (a, b)


pair pa pb = Parser (\s0 ->
case runParser pa s0 of
Left (na, e) -> Left (na, e)
Right (na, s1, a) ->
case runParser pb s1 of
Left (nb, e) -> Left (na + nb, e)
Right (nb, s2, b) ->
Right (na + nb, s2, (a, b)))

Well, that’s a lot. Or perhaps barely anything, if we consider how


many things are going on in this composition, all of which we are
taming in a few lines of rather mechanical code. pair deals with
inputs, with different types of output, with leftovers, with failure,
with error messages, with the length of consumed input, with the
position where a parsing failure occurred, and with making bigger
Parsers out of smaller Parsers. All of that while respecting the
monoidal functor laws, which makes this whole affair terribly
predictable. We wish taming all of this complexity was as
“complicated” as these few lines. Oh, wait, it is. Nice.

Mind you, we are learning, so our implementation has deliberately


been made rather crude and primitive in the sense that it deals with
all of these concerns at the same time, in the same place. But in
reality, these different concerns could be treated separately, and
pair would simply compose all those treatments into one. After all,
we know that a Parser is made out of Functors, and we’ve profited
from this knowledge before when we implemented Parser's own
fmap as fmap . fmap . fmap. Wouldn’t it be nice if we could
implement pair like that, too? Indeed. And we can. And we will.
But not yet.

Compared to the previous implementation of pair, two things


changed. One is that all occurrences of the Right constructor now
carry a three-element tuple of type (Natural, String, x) in it, where
that Natural conveys the number of Chars successfully consumed by
the Parser. The other thing that changed is that in the Eithers we
return after both Parsers have run, the Natural number in question
is now the addition of the number of Chars consumed by both
Parsers. That change is all we need to do in order to make sure that
the relative location of any parsing failure, as well as the relative
number of Chars a successful parsing consumes, convey an absolute
amount with respect to the entire input String initially provided to
runParser.

Finally, assuming we take care of updating our definitions of fmap


and runParser to take the new insides of the Parser datatype into
account, rather straightforward things to do, we can check whether
we accomplished what we wanted.

> runParser (pair parseBool parseBool) "xyz"


Left (0, "Expected 't' or 'f'")
> runParser (pair parseBool parseBool) "tyz"
Left (1, "Expected 't' or 'f'")
> runParser (pair parseBool parseBool) "tfz"
Right (2, "z", (True, False))
> runParser
(pair parseBool (pair parseBool parseBool)) "tft"
Right (3, "", (True, (False, True)))

Beautiful, isn’t it? The take-away from this experiment in taming


complexity, in case it wasn’t made clear by the last hundred
chapters or so, is that it’s not really things what matters, but the
relationships between things. Parsers can be, and that’s fine, but
what’s interesting is how Parsers can be together. And we have
absolute control over that, we decide what it means to compose
things.
165. Attention
There’s a barely noticeable issue in our latest implementation of
pair that we should fix.

When we said na + nb, we created a thunk that, when evaluated,


would result in the Natural value arising from the addition of na and
nb. However, what if na or nb where thunks themselves, as they
would be if they were the result of previous uses of pair? In that
case, we’d be accumulating unevaluated thunks in memory until
the very last moment when somebody decides to evaluate them.
This is not so bad in small examples like ours, but if we
acknowledge that pairing thousands of Parsers is a reasonable thing
to do, then a thousand unnecessary thunks would occupy a
significant amount of memory. We better get rid of them.

pair :: Parser a -> Parser b -> Parser (a, b)


pair pa pb = Parser (\s0 ->
case runParser pa s0 of
Left (na, e) -> Left (na, e)
Right (!na, s1, a) ->
case runParser pb s1 of
Left (!nb, e) -> Left (na + nb, e)
Right (!nb, s2, b) ->
Right (na + nb, s2, (a, b)))

That’s it. All we did is put a bang ! in front of the na and the nbs
that are eventually used in the expression na + nb. This new code
keeps the expression na + nb itself a thunk, but this time the na and
the nb in it are guaranteed to have been evaluated by the time they
are used in this addition. By doing this we prevent creating more
thunks than we actually need.
Are we abandoning laziness by doing this? Not really. By the time
we scrutinize the Either resulting from runParser in order to
disambiguate whether is Left or Right, the parsing function has
already consumed as many Chars from the input String as it needed
in its attempt to successfully parse something, so it clearly knows
the number of Chars in question.

This issue almost went unnoticed, didn’t it? Well, yes, but
remember what we said back when we were studying laziness:
Always make your accumulators strict. And what is this Natural
value, which accumulates the number of Chars consumed so far, if
not an accumulator?
166. Candy
It’s a bit disappointing having to worry about counting those Chars
even when we successfully parse something, isn’t it? Well, that’s
kinda our fault, for we had parseBool do too many things at once.
All we wanted to say, really, is that if the first Char is either 't' or
'f', then we would be able to turn it into True and False, otherwise
parsing should fail with some message of our choice. We don’t
really want to worry about consumed input length nor leftovers.

boolFromChar :: Char -> Either String Bool


boolFromChar = \c -> case c of
't' -> Right True
'f' -> Right False
_ -> Left "Expected 't' or 'f'"

We want something like boolFromChar above. Yes, that’s neat. Can


we have that? Well, not exactly, because it’s not a Parser. But if we
had a function able to convert a value of its type Char → Either
String Bool, or more generally Char → Either String x, to a value of
type Parser x able to deal with all the leftover and position nonsense
inside, then it could work. Yes, let’s build that.

parse1 :: (Char -> Either String x) -> Parser x


parse1 f = Parser (\s0 ->
case s0 of
[] -> Left (0, "Not enough input")
c:s1 -> case f c of
Left e -> Left (0, e)
Right x -> Right (1, s1, x))

parse1 is a higher-order function dealing with all that nasty Parser


business, but deferring any decision about whether the leading Char
in the input String is good or not to the given function f. The name
parse1 reminds us of how hard it is to name things, but hopefully it
also evokes the idea that we are trying to parse exactly one Char from
our input String. Inside parse1, there’s nothing we haven’t seen
before. Having this nice tool, we can redefine parseBool in a rather
neat manner.

parseBool :: Parser Bool


parseBool = parse1 (\c -> case c of
't' -> Right True
'f' -> Right False
_ -> Left "Expected 't' or 'f'")

Excellent. And, by the way, completely unrelated, every time we


find ourselves writing a lambda expression which, after binding an
input to a name, immediately proceeds to perform a case analysis
on it like this:

\x -> case x of A -> …


B | foo -> …
| bar -> …

We can replace it with what Haskell calls a “lambda case”


expression, which essentially replaces that \x → case x of part with
just \case.

\case A -> …
B | foo -> …
| bar -> …
Mind you, this is just syntactic sugar for what we already know. We
are simply avoiding the unnecessary introduction of a name, thus
keeping ourselves from having to worry about it. Additionally, we
are saving ourselves from typing a handful of characters. That’s all.
But, as it sometimes happens with syntactic sugar, it makes things
beautiful. And what would life be without beauty? We live, we die,
and if we do things right, at best beauty is what we leave behind.

This use of the word case reminds us that some words like case,
forall or instance are magically reserved by Haskell for some very
specific purposes, and not for anything else. If we try to implement
a function, say, using these words, the compiler will yell at us.
These words are forbidden, like , or . It’s just a
syntactic matter, not a semantic one.

class :: instance -> instance


class :: \case -> case

Anyway, with the help of \case, our parseBool becomes a bit more
pleasing to contemplate.

parseBool :: Parser Bool


parseBool = parse1 (\case
't' -> Right True
'f' -> Right False
_ -> Left "Expected 't' or 'f'")
167. Small things
With parse1, we can flawlessly parse one Char without having to
worry about Parser details. With pair we can flawlessly compose
Parsers, without having to worry about Parser details. So, in theory,
we have all we need in order to flawlessly parse as many Chars as we
want, again, without having to worry about Parser details.

Not quite, not quite. Eventually we’ll find ourselves wanting to


compose Parsers in a way different than how pair does it. Or two
more ways, actually. At that point, yes, we’ll have finished.
Remember, we control composition, and it’s perfectly fine to have
things compose in many different ways. We know that functions,
for example, compose in at least two ways.

fmap :: (b -> c) -> (a -> b) -> (a -> c)

pair :: (x -> y) -> (x -> z) -> (x -> (y, z))

Nevertheless, we have enough tools now that we can start building


interesting and bigger Parsers using these tools only, without having
to peek inside the Parser datatype again. That’s the rule. We can’t
peek inside Parser. What tools do we have, concretely?

fmap :: Functor f => (a -> b) -> (f a -> f b)

unit :: Monoidal f => f Unit

pair :: Monoidal f => f a -> f b -> f (a, b)

parse1 :: (Char -> Either String a) -> Parser a


And, by the way, notice how only parse1 works exclusively with
Parsers. The rest of our tools require just an f satisfying some
constraint. That is, unless what we build relies explicitly on parse1,
it should work for any such f.

Let’s start by implementing a Parser that deals with an entire String,


rather than an individual Char.

expect :: String -> Parser Unit

The idea is that expect "blue" succeeds if “blue” is at the beginning


of the input String, otherwise parsing fails. expect "blue" expects
“blue” to be there, not something else. expect "" always succeeds,
obviously, for the empty String will always “be” there, not
occupying any space.

Perhaps surprisingly, this Parser returns a meaningless Unit as


output if successful, emphasizing the fact that we are not interested
in deriving any meaning from the String eventually provided to
runParser, but rather, that we are ensuring that the well-known
String we provide as input to the expect function, "blue" in our
example, is present in the raw String being parsed. That’s where this
name comes from, expect. We are just expecting something to be
there, that’s all. In other words, we won’t be using expect for the
output it could produce, but for the side effects it has as a Parser.
That is, we are interested in the current absolute position inside the
Parser being advanced, the leftovers being passed around, and the
failures from parsing being composed nicely, but we are not
interested in this Parser producing any output. Not in the functorial
sense of the word, anyway.
> runParser (expect "blue") "blues"
Right (4, "s", Unit)
> runParser (expect "blue") "blank"
Left (2, "Expected 'u'")

So, how do we write this? Well, we don’t, not yet. expect would be
doing too many things at once, and we need to start getting more
comfortable with the idea of correctly solving the small issues first,
composing the small solutions into a bigger solution afterwards.

If a String is essentially a list of Chars, why don’t we implement a


function expect1 first, of type Char → Parser Unit, doing what expect
would do for an entire String, but just for one Char? That is, expect1
would make sure that the leading Char in the String being parsed is
the expected one. Once we have expect1 working, we could in
theory just pair many of them, one for each Char in the String given
to expect, and this should accomplish our goal.

expect1 :: Char -> Parser Unit


expect1 a = parse1 (\b ->
case a == b of
True -> Right Unit
False -> Left ("Expected " <> show a <>
" got " <> show b))

expect1 'x', say, only succeeds if “x” is the Char at the beginning of
the String being parsed. Otherwise, it fails with a useful error
message.
> runParser (expect1 'x') "xf"
Right (1, "f", Unit)
> runParser (expect1 'x') "yf"
Left (0, "Expected 'x' got 'y'")

Excellent.
168. Chow
We introduced a new function in expect1, one named show.

> :t show
show :: Show a => a -> String

show can be used to convert values of types for which there is a Show
instance, into a String representation of said value. Mainly for
internal display purposes like ours. In expect1 we are trying to
construct a String to use as an error message, and we are using (<>),
of type String → String → String here, to concatenate the smaller
Strings that are part of our message. But the a and the b which we
want to mention in our message are not Strings, so we need to
convert them first. That’s when show comes handy.

Technically, since we know that String is just a type synonym for


[Char], we could have concatenated [a], say, rather than show a.
However, the latter renders the Char more carefully, surrounding it
with single quotes ' and making sure that special Chars like '\n',
more or less corresponding to the “enter” key on our keyboard,
meaning “render a line break here”, don’t actually cause the line to
break, but is instead simply displayed as '\n', which is exactly how
we’d write said Char literally in Haskell. show is not really about
rendering things so that they are pretty, but about making the
details about the value in question very clear to whomever is
reading show's output. So, yes, we prefer using show in our error
messages rather than having to worry about these little details.

show is actually a method of that typeclass called Show.


class Show a where
show :: a -> String

We can implement Show instances for datatypes we define ourselves


quite easily.

data Foo = Bar | Qux Integer

instance Show Foo where


show = \case
Bar -> "Bar"
Qux i -> "Qux " <> show i

See? Easy. Recursive, even. We can now show our values of type Foo.

> show Bar


"Bar"
> show (Qux 8)
"Qux 8"

Actually, we can just not write show and GHCi will automatically
apply show to our values and print the resulting String.

> Bar
Bar
> Qux 8
Qux 8

Among other things, Show is how GHCi knows how to render on


our screen the expressions it evaluates. In fact, look at what happens
if we try to evaluate something for which there is no Show instance,
like functions.

> id
<interactive>:89:1: error:
• No instance for (Show (a -> a)) arising from …

Yes, we get a type-checker error saying that we can’t print the


expression because there’s no Show instance for its type.

Also, tangentially, notice how what GHCi prints looks different


depending on whether we say Bar or show Bar. This is because
whereas the type of Bar is Foo, the type of show Bar is String, and the
respective Show instances for these types, used by GHCi, will do
different things.

Anyway, these Show instances are so straightforward that Haskell


can automatically derive their implementation for us most of the
time. For example, rather than manually writing the Show instance
for our Foo type above, we could have said this:

data Foo = Bar | Qux Integer


deriving (Show)

That line saying deriving (Show) tells Haskell to magically


implement a Show instance for us.

> show (Qux 8)


"Qux 8"

See? Still working. There are actually many typeclasses like Show
which Haskell can automatically derive for us, we’ll talk about
them as they appear. Some we’ve encountered already. Like Eq, the
typeclass that gives us (==) and (/==). We can ask Haskell to derive it
too.

data Foo = Bar | Qux Integer


deriving (Show, Eq)

With this, we can now compare values of type Foo for equality using
(==), something that previously would have resulted in a type-
checking error.

> Qux 4 == Qux 7


False

Anyway, back to our parsers.


169. Bigger things
We have expect1, great. How do we build the expect we described
before with it? Well, it’s rather straightforward, actually.

expect :: String -> Parser Unit


expect = \case
"" -> unit
x : rest -> fmap (const Unit)
(pair (expect1 x) (expect rest))

If expect is asked to parse the empty String, which we agreed should


always succeed because, conceptually, the empty String “is always
there”, then we just use unit as our value of type Parser Unit. We
know that unit will never fail nor affect our parsing in any way, and
this is exactly what we need.

Otherwise, if we are given a non-empty String, as determined by a


successful pattern match on the cons (:) constructor, then we
construct a Parser for the first Char, x, using expect1, and pair it with
a recursive application of expect to the rest of the String. However,
the type of pair (expect1 x) (expect rest) is Parser (Unit, Unit),
not Parser Unit as desired, so we have to fmap the function const
Unit over it in order to convert that (Unit, Unit) output to just Unit.
That’s all. Does it work?
> runParser (expect "") "hello"
Right (0, "hello", Unit)
> runParser (expect "h") "hello"
Right (1, "ello", Unit)
> runParser (expect "hello") "hello"
Right (5, "", Unit)
> runParser (expect "bread") "hello"
Left (0, "Expected 'b' got 'h'")
> runParser (expect "her") "hello"
Left (2, "Expected 'r' got 'l'")

Beautiful. Something interesting about the way in which we’ve


defined our Parser is that, not only will the parsing of the entire
String stop as soon as we encounter an unexpected Char, but also,
due to laziness, the Parsers being paired themselves will not be
constructed at all until it’s been confirmed that indeed they will
need to be executed. This has nothing to do with expect but with
the lazy semantics of pair. We can easily observe this in GHCi using
undefined, our trojan horse.

> runParser (pair (expect1 'a') undefined) "zt"


Left (0, "Expected 'a' got 'z'")

In this example, expect1 'a', the leftmost Parser in our pair, fails, so
the rightmost Parser, our tricky undefined, is not evaluated at all.
This is clever. Not only was the execution of this rightmost Parser
prevented, but zero resources were spent on forcing it out of its
thunk. This is very handy for us when constructing potentially very
large Parsers out of many small Parsers. Because of laziness, the large
Parsers won’t really exist as a process until their existence has been
proven to be necessary by the actual input we are dealing with at
runtime. Very beautiful.
Anyway, lists. Strings are a list of Chars. And if we are saying that we
are performing unit on every occurrence of [], and pair on every
occurrence of (:), then maybe we could express all of this as a fold
instead.

expect :: String -> Parser Unit


expect = foldr
(\x z -> fmap (const Unit) (pair (expect1 x) z))
unit

Indeed. In this partial application of foldr, we are saying that any


occurrence of [] will be replaced by unit, and that any occurrences
of (:) will be replaced by the function where x is the Char currently
in the spotlight, and z is analogous to the recursive call made to
expect rest in our previous example. And, tangentially, since foldr
is lazy in the right way, the lazy semantics of this implementation of
expect are still the same as before.
170. Digital
Let’s build a more interesting Parser now. One that parses a natural
number like “123” into a Natural value. Obviously, we’ll start by
writing the Parser that parses just one Digit, which we’ll most
certainly need. We’ve even seen this Parser before in our examples,
we named it parseDigit. We’ll figure out how to make a Parser for
Naturals out of it later on.

We had a function digitFromChar before, let’s see if we can reuse


that.

digitFromChar :: Char -> Maybe Digit

Building a Parser Digit out of digitFromChar is quite


straightforward.

parseDigit :: Parser Digit


parseDigit =
parse1 (note "Expected a digit 0..9" . digitFromChar)

digitFromChar takes a Char and returns a Maybe Digit, so we compose


this function with note in order to pimp that return type into an
Either String Digit suitable for parse1. This works just fine, of
course.

> runParser parseDigit "8"


Right (1, "", D8)
> runParser parseDigit "v"
Left (0, "Expected a digit 0..9")
How do we go from parsing just one Digit, to parsing a Natural
number made out of many of them? We actually implemented a
function doing just that a while ago, but it had type String → Maybe
Natural rather than Parser Natural. It relied on a function called
sequence with type [Maybe x] → Maybe [x]. Maybe we can use
sequence again?

Back then, we understood sequence as a function that, assuming all


the Maybes in a given list were Just, then the result would also be
Just. Otherwise it would be Nothing. And that was true. However,
what we didn’t know is that this “Nothing vs Just” dichotomy was
just a consequence of pair's behaviour, and that sequence works for
any Monoidal functor, not just Maybe.

sequence :: Monoidal f => [f x] -> f [x]

It might not be immediately obvious, but sequence is essentially pair


in disguise.

pair :: Monoidal f => f a -> f b -> f (a, b)

Let’s do the math. First, let’s uncurry pair.

uncurry pair :: Monoidal f => (f a, f b) -> f (a, b)

Second, let’s acknowledge that a tuple is essentially a two-element


list. However, unlike the elements in a tuple, which can have
different types, all the elements in a list must be of the same type.
We better make our as and bs be a same type, then.
uncurry pair :: Monoidal f => (f x, f x) -> f (x, x)

If we pick that x to be Either a b, say, then we’d still be able to pair


as and bs somehow, by putting one of them in the Left and the
other in the Right, so this change is not a big deal for our
exploration.

What remains now is to make sure we work with lists of xs, rather
than with pairs of xs. And as soon as we have that, we have sequence.

sequence :: Monoidal f => [f x] -> f [x]


sequence = \case
[] -> fmap (const []) unit
fx : rest -> fmap (\(x, xs) -> x : xs)
(pair fx (sequence rest))

If sequence gets an empty list [] as input, that means there’s nothing


to be done, so we just create a decorative f [] out of the blue by
fmapping const [] over the innocent unit.

Hmm. Funny. We keep fmapping const whatever over unit time and
time again. Maybe we should introduce a function that does just
that, and thus avoid some of the noise.

pure :: Monoidal f => a -> f a


pure = \a -> fmap (const a) unit

It’s quite a straightforward function, but we seem to be reaching


out for it quite frequently, so we’d better give it a name. The word
“pure” should remind us that while by looking at the type of the
returned f a we could easily feel inclined to think that f needs to
make some potentially fallible effort in order to produce that a, like
parsing some input or worrying about leftovers, in reality, said a is
being produced in a pure manner where the f part in the f a type
behaves as an identity that does nothing of the sort. And, actually,
look at what happens if we forget about the f for the moment, and
just worry about the a.

id :: a -> a

Oh my, oh my, how exciting. pure is but an oddly shaped identity


function. Naturally, this tells us we are in the right place. We’ll
study this pure transformation in depth later on, but for now, we’ll
just use it to simplify the implementation of sequence a bit.

sequence :: Monoidal f => [f x] -> f [x]


sequence = \case
[] -> pure []
fx : rest -> fmap (\(x, xs) -> x : xs)
(pair fx (sequence rest))

Great. Let’s move on. On the second pattern, when there’s at least
one such value of type f x in that list, then we pair it with a
recursive call to sequence rest. This pairing, however, results in a
value of type f (x, [x]), not f [x] as we wanted. But, by fmaping the
function \(x, xs) → x : xs of type (x, [x]) → [x] over this result, a
function which we could also have written as uncurry (:), we can
convert our Parser's output to the expected type.

If we wanted to use sequence to parse three Digits, say, we could.


parseThreeDigits :: Parser [Digit, Digit, Digit]
parseThreeDigits = sequence (replicate 3 parseDigit)

replicate n x, which we haven’t seen before, is a function that


repeats n times the value x in a list. That is, replicate 3 parserDigit
equals [parseDigit, parseDigit, parseDigit]. Then, we simply
provide this list to sequence. According to GHCi, it works just fine.

> runParser parseThreeDigits "357"


Right (3, "", [D3, D5, D7])

Of course, a parsing failure on any of these Parsers would cause the


entire thing to fail.

> runParser parseThreeDigits "4x6"


Left (1, "Expected a digit 0..9")

If sequence sounds too similar to our recent expect, it is because


expect is a essentially just a special case of sequence.

expect :: String -> Parser Unit


expect = fmap (const Unit) . sequence . fmap expect1

This definition of expect first fmaps expect1 over the input String,
which is just a list of Chars, to create a value of type [Parser Unit].
This list is a suitable input to sequence, which will turn it into a
Parser [Unit], whose output of type [Unit] we are not really
interested in, yet we must convert to Unit in order to keep the
compiler happy. So we fmap the function const Unit over it to finally
get our Parser Unit.
To sum up, while pair allows us to compose two values of in some
Monoidal functor, sequence allows us to compose zero or more of
them. However, this wouldn’t be possible without unit or pure
giving us a sensible answer to the baffling question of what it means
to sequence zero things. sequence brings “successful” things together
in a way that reminds us of how and, the conjunction of many
booleans, does it. Which, by the way, suggests that another way to
look at pair is to think of it as the conjunction of just two functorial
values. If both of these values are “true”, by which we mean that
none of them fail in the sense Left, Nothing or a failing Parser would,
then pair gives us a “true” value as result.
171. Digitoll
Alright, we can parse Digits, and even lists of Digits. We should be
able to parse Natural numbers now. All we have to do, presumably,
is fmap our old function fromDigits, of type [Digit] → Natural, over
our parsing result.

> runParser (fmap fromDigits parseThreeDigits) "325"


Right (3, "", 325)

Amazing. What about parsing a smaller number, like 7?

> runParser (fmap fromDigits parseThreeDigits) "7"


Left (0, "Expected a digit 0..9")

Hmm, this ain’t right. What about a bigger number, like 12345?

> runParser (fmap fromDigits parseThreeDigits) "12345"


Right (3, "45", 123)

What? Why are we only getting 123 as a Natural result, and "45" as
leftovers? Well, the function is called parseThreeDigits, isn’t it? So
this behavior is exactly what we asked for. We parse three digits at a
time, not less, not more, and we make a Natural number out of
them.

But this isn’t really what we want. We want to be able to parse


Natural numbers of arbitrary lengths. We want parseNatural, a
Parser of Natural numbers, with a behaviour like this:
> runParser parseNatural ""
Left (0, "Expected a digit 0..9")
> runParser parseNatural "3"
Right (1, "", 3)
> runParser parseNatural "4159"
Right (4, "", 4159)
> runParser parseNatural "42hello"
Right (2, "hello", 42)

Unfortunately, it turns out we can’t implement a parseNatural like


this unless we poke inside the Parser datatype again. Let’s think
about why.

The first example, where we try to parse a Natural number out of


the empty String, obviously fails because there are no digits we can
parse in this empty String. The second and third examples
successfully parse the full input String into two different Natural
numbers 3 and 4159. However, notice how the String
representations of these numbers have different lengths. This is
different from what parseThreeDigits does when it expects precisely
three Chars. Moreover, even the last example manages to successfully
parse the number 42 out of "42hello", leaving "hello" as leftover for
whomever comes next. Yes, this is what we want.

> runParser (pair parseNatural (expect "he")) "42hello"


Right (4, "llo", (42, Unit))

As it goes about its business, parseNatural most certainly asks itself


whether the fine Char currently in the spotlight is a digit or not, and
makes a decision about whether to continue parsing or not based
on that. Or. We said or. A digit or not. But or means disjunction, it
means Either, it means sum. It doesn’t mean conjunction, product
nor tuples. It does not mean sequence, it does not mean pair.

And we are stuck, because while we’d most certainly be able to


come up with a fascinating implementation of the dubitative
parseNatural if we were to open up the Parser constructor and poke
inside, those are not the rules of the game. We said we’d only build
parsers using fmap, unit, pair and parse1, not the Parser constructor.
We are stuck. We need to compose differently.
172. Open up
Let’s open up Parser again, but only so that we can create a new
way of composing it.

What are we trying to accomplish? We have said, over and over


again, that pair and unit have a correspondence to the product of
types, a monoid with (,) as its associative binary operation and Unit
as its identity element. That’s where the “monoidal functor” name
comes from: Monoidal recreates the monoidal features of product
types for Functorial values.

(,) :: a -> b -> (a, b)


pair :: Monoidal f => f a -> f b -> f (a, b)

Unit :: Unit
unit :: Monoidal f => Unit

The name Monoidal is a bit unfortunate, however, because it


somewhat implies that the product of types is the only monoid for
which we’d want to find a correspondence in Functors, which is
most certainly false. What about the sum of types? Isn’t it true that
composing types together using Either as an associative binary
operation is a monoid with Void as its identity element? Of course
it’s true, and we’d like to have a typeclass for that correspondence,
too.

This typeclass will have two methods. One shall correspond to the
Void type, the identity element for the sum of types, conveying the
idea of zero. And the other shall correspond to the Either type-
constructor, the associative binary operation for this monoid.
Either :: a -> b -> Either a b

Either takes two types a and b, and returns yet another type Either a
b. So, mimicking the correspondence between the tuple type-
constructor (,) and pair, we’ll need a function where the a and b
given as input, as well as the Either a b returned as output, are all
wrapped in some Functor f.

alt :: Functor f => f a -> f b -> f (Either a b)

We’ll call the function alt, suggesting that Parser a and Parser b are
different alternatives. This or that. The correspondence between
Either and alt, regarding their shape at least, is unquestionable.

But alt is not enough. Our monoid needs an identity element too.
In the case of Either, it is Void. For us, it’ll be Void too, but much like
unit wrapped Unit in some Functor f, we’ll wrap Void in an f too.
Let’s call it void, in lowercase.

void :: Functor f => f Void

And since we like a good pun, and moreover we are obliged to rebel
against the misnamed Monoidal, we’ll name our typeclass Monoidalt
and chuckle for a while. We’ll learn, eventually, that neither
Monoidal nor Monoidalt are the names these things go by, so any
discussions about their naming would be rather moot and
temporal. Let’s have fun.
class Functor f => Monoidalt f where
alt :: f a -> f b -> f (Either a b)
void :: f Void

Excellent. We have types. And, obviously, since we are deriving


these ideas from a monoid, we have laws too. First, left and right
identity laws.

alt void a ≈ a

alt a void ≈ a

Then, an associativity law.

alt a (alt b c) ≈ alt (alt a b) c

And finally, a naturality law, which we won’t ever need to prove


manually because of parametricity.

alt (fmap f ma) (fmap g mb) == bimap f g (alt ma mb)

These laws are exactly the same as the Monoidal ones, except we have
replaced all mentions of pair with alt, and unit with void.

Alright then, let’s implement a Monoidalt instance for Parser. Let’s


focus on the alt method first. alt takes a Parser a and a Parser b as
input, and returns a Parser producing a value Either a b that tells us
whether it was the Parser for a or the one for b which succeeded.
The hope is that we will be able to say “parse either this or that”,
and it should work alright.
Let’s see a motivating example first. Let’s compose two Parsers
using alt. One of them will be expect "friend", of type Parser Unit,
which only succeeds if the String being parsed starts with "friend".
The other Parser will be parseBool, of type Parser Bool, converting a
leading 't' in the input String into True, or a leading 'f' into False.
Composing these two Parsers with alt will give us a value of type
Parser (Either Unit Bool), rather than Parser (Unit, Bool) as pair
would.

expect "friend" :: Parser Unit

parseBool :: Parser Bool

alt (expect "friend") parseBool


:: Parser (Either Unit Bool)

First we’ll try to parse "friend", which is exactly the minimum input
our leftmost parser expect "friend" needs to succeed. alt, seeing as
expect "friend" succeeds, proceeds to wrap its Unit output in a Left
constructor that fits the expected Either Unit Bool type.

> runParser (alt (expect "friend") parseBool) "friend"


Right (6, "", Left Unit)

Excellent. It worked. And notice how in this situation, the


rightmost parseBool was completely ignored by alt. The idea is that
alt will only proceed to evaluate the rightmost Parser if the leftmost
fails. For example, expect "friend" would fail to parse an input like
"foe". However, if we use alt to compose it with parseBool, which
would successfully parse Farse from "foe", we will have created a
Parser that because expect "friend" fails, will try doing something
else, and it will succeed at that.

> runParser (expect "friend") "foe"


Left (1, "Expected 'r' got 'o'")
> runParser parseBool "foe"
Right (1, "oe", False)
> runParser (alt (expect "friend") parseBool) "foe"
Right (1, "oe", Right False)

Of course, the Bool output from parseBool is wrapped inside a Right


constructor so as to accommodate the type Either Unit Bool, but
that’s a minor detail. We can see that the False output is still there
on the Right, much like how Unit was on the Left before.

It’s interesting to notice that while expect "friend" won’t


successfully parse "foe", the very first 'f' in "foe" will be
successfully parsed by the expect1 'f' that’s used somewhere inside
the definition of expect "friend". This is communicated to us quite
clearly by the error we get from failing to parse "foe" using expect
"friend":

> runParser (expect "friend") "foe"


Left (1, "Expected 'r' got 'o'")

The error arises when trying to parse the 'o' in position 1, not
before. Yet, despite the leading 'f' having already been consumed
by then, alt, seeing how the leftmost Parser failed, will provide the
entire input String "foe" to its rightmost Parser parseBool, which
will successfully turn that 'f' into False. Not just "oe".

This is an interesting property of alt, and interesting properties


have names. We call it backtracking. We say that the Parser
constructed by alt pa pb will “backtrack” its input in full before
providing it to pb, if pb needs to run at all, despite how much pa may
have consumed. Both pa and pb will receive the same input.

Funnily, even if alt wanted to provide just "oe" to parseBool after a


failed attempt by expect "friend" to parse "foe", it would not be able
to do so, for we were careful enough when designing the Parser
datatype. We made sure that any unsuccessful parsing, as conveyed
by a Left output from the parsing function, does not mention any
leftovers at all. Only a successful parsing result communicates its
leftovers. Clever, right? I’m sure there’s a lesson here about not
putting things in your output that were already part of your input,
unless truly necessary.

What if both Parsers fail, though?

> runParser (alt (expect "friend") parseBool) "water"


Left (0, "Expected 't' or 'f'")

The whole composition fails, of course, what else could happen?


But notice how the error reported by alt is coming from the
rightmost Parser, parseBool. In other words, alt pa pb s biased
towards preserving pa's success, but pb's failure.

Alright, let’s implement alt for Parsers.


alt :: Parser a -> Parser b -> Parser (Either a b)
alt pa pb = Parser (\s0 ->
case runParser pa s0 of
Right (n, s1, a) -> Right (n, s1, Left a)
Left _ -> case runParser pb s0 of
Left x -> Left x
Right (n, s1, b) -> Right (n, s1, Right b))

There’s not much going on here. All that’s happening is that while
pair pa pb only executes pb when pa succeeds, alt pa pb only
executes pb when pa fails, respectively wrapping as and bs in Left
and Right. That’s all.

And just like in pair, the fact that alt doesn’t touch pb unless truly
necessary means that any laziness in pb is fully preserved. We can
observe this by composing undefined, our trojan horse, to the right
of a successful Parser.

> runParser (alt parseBool undefined) "t"


Right (1, "", Left True)

Had alt evaluated that undefined, our program would have crashed.
Alas, that only happens when the leftmost Parser fails.

> runParser (alt parseBool undefined) "x"


*** Exception: Prelude.undefined

What about void, of type Parser Void? This Parser clearly must fail,
for there’s no way we can produce a value of type Void as output.
But failing is easy, we just return a Left with a dummy error
message, and report zero Chars of consumed input.
void :: Parser Void
void = Parser (const (Left (0, "void")))

Does it work? Well, void is supposed to fail by design, so if that’s


what you mean by “work”, then sure, it works.

> runParser void "t"


Left (0, "void")
> runParser (alt void parseBool) "t"
Right (1, "", Right True)
> runParser (alt parseBool void) "t"
Right (1, "", Left True)

pairing with void obviously fails, since this corresponds to the idea
of multiplying by zero, which results in zero.

> runParser (pair void parseBool) "t"


Left (0, "void")
> runParser (pair parseBool void) "t"
Left (1, "void")

In other words, whereas unit always succeeds by doing nothing,


void always fails by doing nothing. And its output value of type
Void, a value impossible to construct, is a testament to this.
173. Digítame
Alright, we have Monoidalt, alt and void now. Can we finally get
parseNatural? That’s what we wanted, right? Of course, here it is.

parseNatural :: Parser Natural


parseNatural = fmap fromDigits (some parseDigit)

Look at how beautiful it is. We parse some digits, and then we


simply fmap fromDigits over them. That’s it. The magic, of course,
happens inside some.

some :: (Monoidal f, Monoidalt f) => f a -> f [a]

some is a function that, given some f a where the f has both Monoidal
and Monoidalt instances, it will return a list with at least one a in it.
We can try some parseDigit on its own to see how this works.

> runParser (some parseDigit) ""


Left (0, "Not enough input")
> runParser (some parseDigit) "1"
Right (1, "", [D1])
> runParser (some parseDigit) "123"
Right (3, "", [D1, D2, D3])
> runParser (some parseDigit) "12y4"
Right (2, "y4", [D1, D2])

That is, as long as one execution of parseDigit is successful, some


parseDigit will succeeded. The return type some is a bit
disappointing, seeing as [a], as far as the type system is concerned,
could be an empty list, but in fact this will never be the case. We’ll
come back to this later. For now, let’s implement some. Actually,
let’s implement optional first, a smaller function that some will
benefit from.

optional :: (Monoidal f, Monoidalt f)


=> f a -> f (Maybe a)

While alt fa fb executes fb if fa fails, optional fa never fails.


Instead, it replaces failures in fa with a “successful” Nothing result.
In a sense, optional demotes failures in f to failures in Maybe. We can
try optional in GHCi and see how this works in practice.

> runParser (optional parseBool) "f"


Right (1, "", Just False)
> runParser (optional parseBool) "hello"
Right (0, "hello", Nothing)

See? In both cases runParser returns Right, even when parseBool


could not parse "hello" into a Bool. In that case, optional replaced
that parsing failure with a successful Nothing result. The
implementation of optional is quite straightforward:

optional
:: (Monoidal f, Monoidalt f)
=> f a -> f (Maybe a)
optional fa =
fmap (either Just (const Nothing))
(alt fa unit)

We simply compose fa with unit using alt, meaning that alt fa


unit will always succeed even if fa fails, for unit itself never fails, so
at worse alt fa unit will successfully produce Right Unit. Finally,
we use fmap to convert the Either a Unit produced by alt fa unit to
the isomorphic and more ergonomic Maybe a. We see both Monoidal
and Monoidalt constraints in this function because we are using both
unit and alt, methods belonging to these different typeclasses.
Having optional, defining some is just a small step.

some :: (Monoidalt f, Monoidal f) => f a -> f [a]


some fa = fmap (\(a, yas) -> a : maybe [] id yas)
(pair fa (optional (some fa)))

some fa requires at least one execution of fa to succeed, but it will


collect the results of as many successful executions of fa as it can
before finishing its work. From this idea follows that some must pair
one execution of fa with an optional execution of a recursive call to
some fa. That’s all. If that first fa fails, then the whole thing fails,
but as long as it succeeds, then whether any following executions of
fa succeed or not is irrelevant, some will succeed nonetheless. Finally,
since pair fa (optional (some fa)) has type f (a, Maybe [a]), we
fmap over it a function that converts all of that to [a]. And we can
see here that, indeed, this returned list will never be empty, even if
the type [a] says otherwise. We’ll fix that later on.
174. Nearly
There aren’t nearly as many Functors for which we can provide
implementations of alt and void compared to those for which we
can implement pair and unit, considering alt only makes sense for
Functors that have some concept of “success” and “failure” like
Parser does. Maybe is one of those few.

instance Monoidalt Maybe where


void = Nothing

alt (Just a) _ = Just (Left a)


alt _ (Just b) = Just (Right b)
alt _ _ = Nothing

For Maybe, Nothing means failure and Just success.

> alt Nothing Nothing


Nothing
> alt (Just True) Nothing
Just (Left True)
> alt (Just True) (Just False)
Just (Left True)
> alt Nothing (Just False)
Just (Right False)

And, as expected, the rightmost Maybe is not evaluated unless strictly


necessary. Laziness is preserved.

> alt (Just True) undefined


Just (Left True)
Using alt with Maybe allows us to check whether we have one thing,
or the other, or Nothing at all.
175. Other things
Monoidal is where the fun’s at. What other things can we sequence?
We tried Maybe and Parser already. Let’s try Either String next. To
keep things neat, let’s say all of the expressions below are of type
Either String [Natural].

> sequence []
Right []
> sequence [Left "red"]
Left "red"
> sequence [Left "red", Left "blue"]
Left "red"
> sequence [Left "red", undefined, Right 4]
Left "red"
> sequence [Right 3, Left "red"]
Left "red"
> sequence [Right 2]
Right [2]
> sequence [Right 4, Right 1, Right 8]
Right [4, 1, 8]

Essentially, Either String —or Either whatever, really— behaves just


like Maybe.

What about functions next? Let’s see what happens if we pick (→)
Natural to be our Monoidal functor, and assume we’ll be using
sequence on lists containing values of type Natural → Bool. Let’s try
with the function named even first, of type Natural → Bool,
returning True if the given number is even or False otherwise.
> even 4
True
> even 3
False
> :type sequence [even]
sequence [even] :: Natural -> [Bool]
> sequence [even] 4
[True]
> sequence [even] 3
[False]

Interesting. What about putting more functions of type Natural →


Bool in that list?

> sequence [even, odd] 4


[True, False]
> sequence [even, odd] 3
[False, True]
> sequence [even, odd, \x -> x == 5] 3
[False, True, False]
> sequence [even, odd, \x -> x == 5, \x -> x < 10] 3
[False, True, False, True]

Fascinating. Like pair and (&&&), sequence still fans-out, but it does
so on a larger scale.

> sequence [(+ 1), (* 10), \x -> x * x] 3


[4, 30, 9]

What other Monoidal functor do we know? What about lists? They


are a Functor, right? Wait, wait, wait, we never discussed this. Are
we saying lists are Monoidal functors? How?
176. René
For something to be a Monoidal functor, it needs to implement unit,
pair and satisfy a bunch of laws. Well then, if we can do that for
lists, we’ll have discovered a new Monoidal functor. Can’t wait to see
what it does!

instance Monoidal [] where


unit :: [Unit]
pair :: [a] -> [b] -> [(a, b)]

Interesting. It’s unclear what unit should do. Should it be an empty


list? Hmm, perhaps not, seeing how that would be akin to unit
being Nothing in the case of Maybe, which we already know is
incorrect. Should it be a list with one Unit in it? What about seven
Units in it? What about it being an infinite lists of Units? Interesting
questions. But, considering this function is called unit, evoking the
idea of one, let’s try our luck with a list containing exactly one Unit
in it and see what happens. If necessary, we’ll have the opportunity
to repent and change our decision later on.

unit :: [Unit]
unit = [Unit]

What about pair? The type says it takes a list of as and a list of bs,
and it turns them into a single list of as and bs. So, presumably, it
just pairs the individual elements of these lists in order.

pair :: [a] -> [b] -> [(a, b)]


pair (a : as) (b : bs) = (a, b) : pair as bs
pair _ _ = []
Like in the case of Maybe, we only seem to be able to produce a list
containing tuples of as and bs when the lists given as input are
themselves not empty. Do we have a monoidal functor? Well, let’s
check if our chosen unit and pair satisfy the monoidal functor laws.
First, for any list x, pair x unit, x and pair unit x should all be
isomorphic. Let’s pick some lists and try. Let’s try with the empty
list first.

> pair [] unit


[]
> pair unit []
[]

Alright, this seems fine. Let’s try a list with one element next.

> pair [4] unit


[(4, Unit)]
> pair unit [4]
[(Unit, 4)]

Excellent. These results are isomorphic to [4]. What about a list


with two elements in it?

> pair [5, 7] unit


[(5, Unit)]
> pair unit [5, 7]
[(Unit, 5)]

What? That’s not right. Where did the 7 go? The identity law for
monoidal functors has been violated. Did we pick the wrong unit?
No, actually, we picked the wrong pair. The function we
implemented is not pair, but a function called zip.
zip :: [a] -> [b] -> [(a, b)]
zip (a : as) (b : bs) = (a, b) : zip as bs
zip _ _ = []

zip is useful when you have two lists of the same length, and you
want to pair up the individual elements of those lists in the same
order they appear on those lists.

> zip [1, 2, 3] [100, 200, 300]


[(1, 100), (2, 200), (3, 300)]

However, when one of the given lists is shorter than the other one,
all the “extra” elements from the longer lists are simply dropped
from the result.

> zip [1, 2, 3] []


[]
> zip [1, 2, 3] [100]
[(1, 100)]
> zip [1, 2, 3] [100, 200, 300, 400, 500, 600]
[(1, 100), (2, 200), (3, 300)]

What failed when we tested for the identity law is that we were
trying to zip a list of length one, unit, with a longer list, and this
caused all the elements beyond the first one to be discarded.

Can we pair lists, then? Yes, yes we can, but the answer is
something else. We need to implement the cartesian product of
these lists, where each element on one list is paired exactly once with
each element on the other list:
> pair [1, 2, 3] [True, False]
[(1, True), (1, False),
(2, True), (2, False),
(3, True), (3, False)]

You see, all of 1, 2 and 3 are paired with both True and False. And,
symmetrically, all of True and False are paired with 1, 2, and 3. If we
were to pair with unit, the result would be isomorphic to the given
list.

> pair [1, 2, 3] unit


[(1, Unit), (2, Unit), (3, Unit)]
> pair unit [1, 2, 3]
[(Unit, 1), (Unit, 2), (Unit, 3)]

And pairing with the empty list, obviously leads to an empty result.

> pair [5, 6, 7] []


[]
> pair [] unit
[]

Let’s implement pair, then. We said we want to pair each element


of one list, to each element of the other list. Well, fmap is how we
address “each” element of a list, so presumably we are saying we’ll
somehow need to fmap twice, once for each list.

pair :: [a] -> [b] -> [(a, b)]


pair = \as bs ->
mconcat (fmap (\a -> fmap (\b -> (a, b)) bs) as)
Indeed. Let’s pay attention to the fmap (\a → …) as part first. This is
saying that each element of the list named as, the first parameter to
pair, will be transformed somehow using the function given as first
parameter to this fmap. This function, however, has another use of
fmap in it. \a → fmap (\b → (a, b)) bs says that each element in bs
will be paired up with the a coming from as that’s currently in the
spotlight. If, for example, as was [1, 2, 3] and bs was [True, False],
then this code would first select 1 to be a and True to be b, then it
would keep a as is but move on to picking False as b, and only then,
after bs has been exhausted, would 2 become a and the process
would continue until as is exhausted.

However, if we consider that the type of the function we are


fmapping over as is a → [(a, b)], and that generally speaking fmap for
lists means lifting a function of type x → y into a function of type
[x] → [y], then lifting a function type a → [(a, b)] will give us
something of type [a] → [[(a, b)]]. But do you see those double
brackets around (a, b)? We don’t want them. This is where mconcat
comes in.

If we recall, lists are Monoids too, and when we have a list of Monoids,
we can use mconcat, of type Monoid m ⇒ [m] → m, to mappend all of those
ms together. So if we pick [x] to be our m, for some arbitrary x, then
mconcat adopts the type [[x]] -> [x] and simply concatenates lists
together, seeing how list concatenation is how mappend combines
values of type [x].
> mconcat []
[]
> mconcat [[]]
[]
> mconcat [[], []]
[]
> mconcat [[], [1, 2], [3]]
[1, 2, 3]
> mconcat [[1, 2], [], [3, 4], [5]]
[1, 2, 3, 4, 5]

So, yes, lists are Monoidal functors too, and pairing them gives us the
cartesian product of the given lists. I leave it up to you to prove,
using equational reasoning, that the Monoidal functor laws hold for
our chosen unit and pair. Here’s the full definition of the Monoidal
instance for lists.

instance Monoidal [] where


unit :: [Unit]
unit = [Unit]
pair :: [a] -> [b] -> [(a, b)]
pair = \as bs ->
mconcat (fmap (\a -> fmap (\b -> (a, b)) bs) as)

What could sequence do for lists?

sequence :: Monoidal f => [f a] -> f [a]

This question becomes even more intriguing when we realize that


our f will be the type-constructor []:
sequence :: [[a]] -> [[a]]

Well, seeing how pair gives us the cartesian product of two lists, and
how sequence is essentially pair but for zero or more lists rather than
two, sequence will presumably give us the cartesian product of all
the input lists.

> sequence []
[]
> sequence [[]]
[]
> sequence [[], []]
[]
> sequence [[1, 2], [3, 4, 5]]
[[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]
> sequence [[1, 2], []]
[]
> sequence [[1, 2], [], [3, 4, 5]]
[]
> sequence [[1, 2], [3], [4, 5, 6]]
[[1, 3, 4], [1, 3, 5], [1, 3, 6],
[2, 3, 4], [2, 3, 5], [2, 3, 6]]

Indeed. Beautiful. Notice how the number of lists we obtain as


result of using sequence equals the multiplication of the lengths of
the lists given to it:

> sequence [[1, 2], [3, 4, 5]]


[[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]

The length of [1, 2] is two, the length of [3, 4, 5] is three, thus the
length of the list returned by sequence [[1, 2], [3, 4, 5]] is three
times two, six. Following this reasoning, we can see how including
an empty list [], whose length is zero, among the input to sequence,
would lead to an empty list as result. Multiplying by zero results in
zero.

> sequence [[1, 2], [], [3, 4, 5]]


[]

Another interesting property of the list resulting from sequence is


that, provided there are no empty lists among the input, all of the
individual lists returned by sequence will have the same length,
which will equal the number of lists that were provided to sequence
as input. For example, if we provide two lists as input to sequence, in
return we get a list of lists of length two:

> sequence [[1, 2], [3, 4, 5]]


[[1, 3], [1, 4], [1, 5], [2, 3], [2, 4], [2, 5]]

Here we provide four:

> sequence [[1], [2, 3], [4], [5]]


[[1, 2, 4, 5], [1, 3, 4, 5]]

And here, just one:

> sequence [[1, 2, 3]]


[[1], [2], [3]]

sequence is fun. With it, for example, we can multiply as René


would.
> fmap product (sequence [[1, 2], [3, 4, 5]])
[3, 4, 5, 6, 8, 10]
177. Cease
We’ve said time and time again that as long as we know how to
compose two things in a monoidal kind of way, we can compose as
many of them as we need, sometimes infinitely many. And this is
true for both pair and alt.

Imagine we had a product type named Foo with four fields in it.

data Foo = Foo Natural Bool Digit Bool

Could we use pair to, say, construct a Parser for Foo? Of course.

parseFoo :: Parser Foo


parseFoo = fmap (\(a, (b, (c, d))) -> Foo a b c d)
(pair parseNatural
(pair parseBool
(pair parseDigit
parseBool)))

This works as expected.

> runParser parseFoo "1234f8t"


Right (7, "", Foo 1234 False D8 True)

However, hopefully we can agree that the implementation of


parseFoo is rather inconvenient. It is simple, yes, we just use pair as
many times as necessary and fmap a rather straightforward function
over the parsing result in order to construct a Foo, but it is not very
ergonomic. Imagine if Foo had ten more fields. Then, the
implementation of parseFoo would be much longer and distracting.
What about sum types? What if we wanted to parse a datatype like
Season, having four constructors?

parseSeason :: Parser Season


parseSeason =
fmap (\case Left Unit -> Winter
Right (Left Unit) -> Spring
Right (Right (Left Unit)) -> Summer
Right (Right (Right Unit)) -> Autumn)
(alt (expect "winter")
(alt (expect "spring")
(alt (expect "summer")
(expect "autumn"))))

That’s… unfortunate. There is beauty in alt's simplicity, but that


doesn’t necessarily make alt an ergonomic solution. Half of
parseSeason's implementation is spent simply rearranging alt's
output using fmap, and doing this time and time again get’s
frustrating rather quickly. But there is an alternative.

(<|>) :: Monoidalt f => f x -> f x -> f x


fa <|> fb = fmap (either id id) (alt fa fb)

This function, (<|>), intended to be used as an associative infix


operator, is essentially just alt. However, rather than taking
functorial values of different types f a and f b as input, eventually
returning an f (Either a b) as output, it takes inputs of a same type
f x, making it possible to forego the produced Either output, and
instead simply return an f producing the leftmost x that succeeded.
And with this, we can implement parseSeason in very concise way.

As always, let’s start by solving the smaller problems first. Let’s start
by implementing Parsers for each Season individually.

parseWinter :: Parser Season


parseWinter = fmap (const Winter) (expect "winter")

parseWinter shares its type with parseSeason from before, but rather
than worring about all four possible Seasons, it worries only about
Winter. How? It expects "winter" to lead the input String being
parsed, and if it does, then this Parser's boring Unit output will be
replaced with Winter by simply fmapping const Winter over it.

> runParser parseWinter "winter"


Right (6, "", Winter)

And we can do the same for the rest of the Season values.

parseSpring :: Parser Season


parseSpring = fmap (const Spring) (expect "spring")

parseSummer :: Parser Season


parseSummer = fmap (const Summer) (expect "summer")

parseAutumn :: Parser Season


parseAutumn = fmap (const Autumn) (expect "autumn")

An with this, we have constructed the four Parsers that could, in


principle, add up to the totality of what it means to parse a Season.
All we need to do now is compose them into a bigger Parser. And
seeing how the Parser we ultimately want, parseSeason, has the same
type as the four Parsers we just defined, Parser Season, we can go
ahead and use <|> to do it.
parseSeason :: Parser Season
parseSeason = parseWinter <|> parseSpring <|>
parseSummer <|> parseAutumn

As confirmed by GHCi, this works as expected.

> runParser parseSeason "winter"


Right (6, "", Winter)
> runParser parseSeason "spring"
Right (6, "", Spring)
> runParser parseSeason "summer"
Right (6, "", Summer)
> runParser parseSeason "autumn"
Right (6, "", Autumn)

We’ve made alt a bit more ergonomic, that’s all. Interestingly, as we


said, <|> is an associative binary operation, and whenever we have
one of those, we should ask ourselves whether there is an identity
element too. Because if there is, then we’ll have a monoid.
Obviously, knowing that alt formed a monoid, and how <|> is just
alt in disguise, we expect there’ll be an identity element too.

However, considering the type of (<|>) is Monoidalt f ⇒ f x → f x →


f x, for all x, then our identity element will have to be of type ∀ x.
Monoidalt f ⇒ f x. For all x, not just Void as it’s been so far. Well,
that’s easy.

empty :: Monoidalt f => f x


empty = fmap absurd void

Remember absurd? It was that function of type ∀ x. Void → x saying


“give me a Void and I’ll give you anything you want”, a bluff. And,
sure enough, the type of void, Monoidalt f ⇒ f Void, says there could
be a Void someday. So, taking inspiration from politicians, all we
need to do is keep lying, fmap the absurd over the void, lies on top of
lies, into what will be our deepest lie yet, for there will never be a
Void, thus there will never be an x, yet there will be a zero, the
identity element for our monoid. We call it empty, and together with
<|>, they form the Alternative typeclass, which is how our
exploratory Monoidalt, alt and void manifest themselves in Haskell.

class Functor f => Alternative f where


empty :: f x
(<|>) :: f x -> f x -> f x

Monoidalt doesn’t exist. Nor alt, nor void. All we have is Alternative
and its methods. We’ll never write a Monoidalt instance for Parser,
say, because the Monoidalt typeclass doesn’t exist. But we will write
an Alternative instance for Parser.

instance Alternative Parser where


empty :: Parser x
empty = Parser (const (Left (0, "empty")))

(<|>) :: Parser x -> Parser x -> Parser x


pa <|> pb = Parser (\s0 ->
case runParser pa s0 of
Right r -> Right r
Left _ -> runParser pb s0)

The implementation of the Alternative instance is even simpler


than that of Monoidalt, since we don’t need to worry about
massaging a and b into Either a b. We can keep our efforts to a
minimum and do what we said we wanted to do, which is run pb
only if pa fails. That’s all. The implementation for empty, despite
having a different type and a different error message, is exactly the
same as void's. The type of empty says there could be an x, but empty
will never produce such x. No promises are broken.

Of course, once we have empty and <|>, if for some reason we want
void and alt back, we could define them on terms of empty and <|>.
void is easy, seeing as it’s just a less polymorphic version of empty.
We don’t need to do anything.

void :: Alternative f => f Void


void = empty

And alt is not much more complex than this, really. Essentially, we
need to do something similar to what we did when parsing Seasons
using <|>, but for Either rather than for Season.

alt :: Alternative f => f a -> f b -> f (Either a b)


alt fa fb = fmap Left fa <|> fmap Right fb

That’s it. The Alternative instance for Maybe is quite straightforward


too:

instance Alternative Maybe where


empty :: Maybe x
empty = Nothing

(<|>) :: Maybe x -> Maybe x -> Maybe x


Just x <|> _ = Just x
_ <|> Just x = Just x
_ <|> _ = Notihng
That’s the story of how Monoidalt ceased to be.
178. Soup
Infix operators are, generally speaking, uncomfortable to use
outside textbook scenarios. Mainly because it’s hard to tell how
adjacent expressions using these operators associate unless we put
parenthesis around them. Luckily, this is not a textbook, so we’ll
take this into account.

Consider for example 2 + 4 / 5 * 3 / 4 / 5 - 2 / 2 * 3. Even if we


have been doing arithmethic all our lives, chances are we’ll need to
stop for a while in order to contemplate and understand how the
expressions we just wrote, using what we call an infix operator soup,
associate with each other.

In Haskell we compose many expressions, and the less infix


operators the use, the easier it will be to understand what’s going on
at a glance. Even more so knowing that these operators may, at
times, be partially applied. Perhaps it won’t be necessarily easier on
our eyes as we write these expressions for the first time, but it will
certainly be easier for those who come to read them afterwards.
Which, by the way, includes our future selves too.

With this in mind, we’ll present an alternative and enlightening way


of defining parseSeason, say, avoiding the use of <|>.

parseSeason :: Parser Season


parseSeason = asum [parseWinter, parseSpring,
parseSummer, parseAutumn]

Having seen the previous definition of parseSeason using <|>, we


should be able to decipher what asum is doing by just thinking about
it. asum will try as many Parsers as it needs from the given list, from
left to right, until one of them successfully produces a value of type
Season. If none of them do, then the whole Parser constructed by
asum fails. The definition of asum is very straightforward.

asum :: Monoidal f => [f a] -> f a


asum = foldr (<|>) empty

If you recall, one of our intuitions for foldr is that all occurrences
of (:) in the list are replaced by the given binary operation, and [] is
replaced by the given initial accumulator. In our case, we replace
them with (<|>) and empty.

The list provided to asum in our parseSeason example could have


been written using (:) and [], rather than Haskell’s [funny, list,
syntax]:

parseSeason = asum (parseWinter : parseSpring :


parseSummer : parseAutumn : [])

Replacing those (:) and [] for <|> and empty, as asum would, takes us
back to where we started:

parseSeason = parseWinter <|> parseSpring <|>


parseSummer <|> parseAutumn <|> empty

Well, not exactly. We have a superfluous empty at the end. That’s


not too bad, seeing as this doesn’t change the meaning of our
parser. It does, however, change the error message with which
parseSeason fails, seeing how if parseSeason fails, it will be empty's
fault and not parseAutumn's. Perhaps we don’t want that. Who
knows what kind of important message is there on that error? Let’s
write asum differently so that we preserve the error from the last
element of the list, if any.

asum :: Monoidal f => [f a] -> f a


asum [] = empty
asum [fa] = fa
asum (fa : rest) = fa <|> asum rest

Quite straightforward. All we did is prevent any further recursion


into asum whenever we recive a list with a single element as input, as
matched by the second pattern above. This effectively means empty
will only happen if asum is applied to [] by an outside caller, because
asum will never recursively apply itself to the empty list [], making
sure any errors arising from that last f a in the input list, if any, are
preserved.

It’s interesting to highlight that whereas there is a direct


correspondence between sequence and the conjunction of booleans,
in the sense that sequence requires that all the functorial values
given to it succeed or “be true”, there is also a direct
correspondence between asum and the disjunction of booleans,
seeing how asum expects at least one of them to succeed. At least
one, any one. sequence and asum are the functorial versions of and
and or.

Here are some examples of and and sequence, assuming we are


dealing with functorial values of type Maybe Natural.
> and []
True
> sequence []
Just []
> and [True, False]
False
> sequence [Just 3, Nothing]
Nothing
> and [True, True]
True
> sequence [Just 3, Just 4]
Just [3, 4]

And here are or and asum, for comparison:

> or []
False
> asum []
Nothing
> or [False, False]
False
> asum [Nothing, Nothing]
Nothing
> or [False, True]
True
> asum [Nothing, Just 4]
Just 4

Alright. What about Monoidal, unit and pair? Can we get rid of
them, too? Is that something we want to do? Why are we asking
these questions?

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy