Lecture slides and video links #
As the course progressed, I added the annotated slides and live code examples, along with links to the videos (accessible with a Durham account), and some commentary.
2022-01-10: Annotated slides, video, code
We got most of the way through the slides, and then did some live examples. We same some very simple functions and probably quite a lot of syntax that we’ll go through in more detail as the course progresses.
My editor was a bit angry fruit salad, which I’ve toned down for next time.
I would encourage you to get a fancy editor setup so that you too can take advantage of the “code actions” I was using, these are provided through LSP by the Haskell wingman.
2022-01-14: Annotated slides, video, code
We finished off by going over the definition of
filter
we had seen at the end of the last session. I’ve updated the lecture 1 annotated slides above to include my new annotations (I wrote it out more neatly).We then did some introductory types and started hinting at the idea that function types, and especially higher-order functions, are very important. We got about halfway through the slides, and I’ll pick up there next time.
Gary Bernhardt has a fun talk about type errors, mostly in javascript.
2022-01-17: Annotated slides, video, code (finishing session 2) and starting session 3
We finished off a few slides from session 2 (and I updated the annotated ones above). Then we spent quite a lot of time looking at defining functions and in particular discussing currying and why Haskell tends to prefer functions written in curried form.
Then I showed a few session 3 slides and talked about polymorphic functions and monomorphisation. We’ll pick up there next time and continue with session 3 stuff.
2022-01-21: video, code (finishing session 3)
We didn’t see any slides this time and instead worked our way through the definitions of some polymorphic functions. The main focus was on figuring out how we might be able to write total functions which are functions which produce valid results for all possible inputs. To do so, we introduced the
Maybe
data type, which models a computation that may fail.We then saw that to constructively work with
Maybe
types we are likely going to need a way to transform values that live “inside”Maybe
s and introduced a functionapplyInsideMaybe
whose type signature bore a striking resemblance to that ofmap
, which is approximately where we will start next time.2022-01-24: annotated slides (updated from session 3), video, code
We talked a little bit about Haskell type classes and how they are used to implement constrained generic programming: that is writing generic functions that can specify interfaces that the arguments should satisfy.
The wikipedia page has a nice overview as usual on polymorphism. The classic work on subtyping is from Barbara Liskov from 1987. The method that Haskell uses for constrained (ad-hoc) polymorphism based on type classes was introduced by Phil Wadler and Stephen Blott in How to make ad-hoc polymorphism less ad hoc. Here’s a video of Simon Peyton Jones giving an introductory talk on type classes and their implementation in GHC.
We implemented our own linked list type and and discussed pattern matching a bit more.
We just did code today, in particular we systematically looked at a method for writing recursive functions. We have effectively covered the slides up to lecture 5 (as uploaded on blackboard), we just started hinting at folds in the last part of the session 5 slides.
We saw that a number of “library” functions on lists follow the same pattern, and we sketched a higher order function that captures this pattern.
I showed a way to find functions in the Haskell standard library (and packages) if you know the type by using hoogle.
2022-01-31: annotated slides, video, no code today
We introduced, following on from looking for patterns,
foldr
andfoldl
and saw how they can be seen on lists as rebuilding the structure with a new binary operator (instead of(:)
) and initial element (instead of[]
).We then also looked at two “principled” type classes, namely
Functor
for mappable types, andFoldable
, for foldable types.The type classes are termed “principled” because their implementations are expected to satisfy certain equational laws that mathematically capture certain properties that an implementation must obey so that it behaves “as expected”. We saw the
Functor
laws, but not theFoldable
laws (which need more time than we have here). Note that although I often ask you to implementFunctor
andFoldable
instances, GHC can actually derive them for you if you add{-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE DeriveFoldable #-}
at the top of your files.
I’ve diverged a bit from the slides uploaded to blackboard, although I have covered the material in a combination of the slides you’ve seen and the live code: you may wish to browse the slides as well to compare with the code we’ve seen.
2022-02-04: annotated slides, code, video
I finished the declarations for
Functor
andFoldable
instances for theMaybe
,BinaryTree
, andRoseTree
data types we’d seen. Then we talked about how Haskell evaluations expression graphs and how we can do strict (eager) evaluation with($!)
. I rushed through the last few slides a little bit so will go over them again briefly on Monday to wrap up the lazy evaluation aspects and then talk about data encapsulation and compile-time safe APIs.2022-02-07: annotated slides, code (and main file, video
I showed differences between strict and lazy evaluation for some simple folds in terms of performance (particularly between
foldl
andfoldl'
), though noted for this simple example that GHC does a good job determining that it can evaluate things strictly. For more details on this, see the haskell wiki.I then talked about the design of APIs and “type-driven design”, and how a rich type system can help us in the design of libraries that are in some sense impossible to misuse.
This style of interface is becoming more popular because it pushes a bunch of the complexity of keeping track of invariants onto the type system and compiler (rather than the programmer’s brain).
In Haskell-ese an often quoted mantra is to “make illegal states unrepresentable”.
If you’re interested in this kind of stuff, here are some starting points for further reading
- Alexis King has a nice article on the idea of parsing rather than validating
- The Rust community has really got on board with type state patterns
- Matt Noonan shows how
Haskell can provide enough dependent types to encode quite
complicated invariants (such as the
mergeBy
example in the lecture) in the type system. - If you’re interested in formal methods and proof systems, Talia Ringer has an introductory course on proof automation, and Kevin Buzzard writes a lot about formalising mathematics in Lean.
2022-02-11: annotated summary slides, slides on IO actions (didn’t show these, only did the code), code, video
We talked a little bit about doing I/O in a pure language, which forced us to introduce the concept of actions. I showed some information about
do
notation for peeking inside them, and how conceptually, doing I/O can be seen as taking the state of the universe and producing a new state. The main takeaway is that we have to wrap up impure “actions” so that we don’t break referential transparency in the language.I then summarised the course and talked a little about what I think the important bits are.
There were some questions about pointers to bigger programs in Haskell. For self-contained things, you might look at the Imperial January Haskell tests. For bigger things you might start at the Haskell wiki. One thing to note is that lots of the libraries in the wild will use more advanced features than we saw in the course (but maybe that’s helpful).
The resources section of the front page also has some pointers.
Next term there will be a revision lecture scheduled, but this was my last term in Durham, so it will come from someone else. Look out for announcements via ULTRA.
Thanks again everyone, and enjoy!
2022-04-25: Revision slides, video