Lecture 1 — 2020-01-21
Introduction
This lecture is written in literate Haskell; you can download the raw source.
To understand craftsmanship, we must ask not only “What has been made?” and “How has this been made?” but also “Who made this and why?” Craftsmanship is a relationship between the maker and the process of creation. It is not simply a set of skills one acquires, like the ability to read or drive a car. More than anything, craftsmanship is a matter of attitude: why we choose to devote time to such a demanding endeavor, why we choose to make a certain object of a certain appearance, and how we go about it.—Peter Korn, Woodworking Basics: Mastering the Essentials of Craftsmanship
Let’s get started. Here’s a simple arithmetic function:
We can make an ordinary function infix using backticks:
Run ghci
to test your program. Here are some more interesting, recursive functions:
There are conditionals:
Here’s the pipe form for conditionals within a top-level pattern match:
The following code is redundant and poorly typeset.
fact'' :: Int -> Int
fact'' 0 = 1
fact'' 1 = 1
fact'' 2 = 2
fact'' n = if n < 0 then 1
else n * fact'' (n - 1)
But don’t get the wrong idea: you can have more than one base case, if you like.
Here’s an “accumulator passing” function, using a where
clause to nest a local definition. Can you see how fibAux
is like a loop?
fib' :: Int -> Int
fib' n = fibAux 1 1 n
where fibAux f2 f1 0 = f2
fibAux f2 f1 n = fibAux f1 (f1+f2) (n-1)
To see how important type annotations are to getting good error messages, try removing the type annotation on fibAux
and forgeting to apply fibAux
in the third case.
Here’s our first datatype, representing the days of the week.
Note the use of capital letters for the type itself (Day
) and for its constructors (Monday
, etc.). Try using these constructors in ghci
.
Here’s simple function to determine whether or not it’s party time; note how the wildcard pattern _
doesn’t bind any names and matches anything.
Top-level definitions in Haskell automatically do pattern matching, but we can be explicit if we like:
I think isWeekend'
’s definition is slightly less good than isWeekend
: why do an expression-level match when we could have matched at the top-level?
Let’s define isWeekday
in terms of a function we already have:
But we can also use the math-like composition operator:
Before you go on, try to guess (.)
’s type. It’s an ordinary function!
Finally, note that booleans aren’t builtins in Haskell. Somewhere in the Prelude (the standard definition), someone defined the booleans:
data Bool = False | True
And we could even define our own conditional: