A continuation of my iterative review of the early access edition of Haskell Programming from First Principles. I cover my experiences of the last month working through chapters 5 through 10.
This month has been challenging, not because the book has gotten too hard, but because work has thrown more projects at me than I can carry comfortably and then thrown more at me as I dug in on my time to move them off the board. More fool me. I'll never learn.
Anyway, this isn't about me, it's about Haskell Programming from First Principles!
I worked through chapters 5 through 10 of the book:
The typeclasses chapter is a masterpiece. It's easily my favorite chapter so far. I have not seen a more effective exploration of the topic yet. I came away from it feeling renewed confidence in my intuitions about types, polymorphic types, and constrained polymorphic types. A major change in my thoughts on function use came from it as well. I no longer reach for typeclass functions if I have concrete types. Using typeclasses just for the sake of it is silly and obscures the intent of my code. A particular highlight of this chapter is the exploration of subclasses and equivalence. That is a non-trivial topic and I found myself digging in pretty deeply on Hoogle to explore it. In most cases GHCi made the questions easy to answer, but I'm honing my Haskell pair programming skills so I'd like to be able to do these things without an interpreter or IDE at hand. I felt like this chapter prepared me very well for that.
More functional patterns felt like a tour of a serious carpenter's toolbox, but I think that is the intention. It explores a number of useful techniques for unpacking code you are reviewing. Working through exercises exploring the varied equivalent forms of anonymous functions (lambdas) versus multi-argument (auto-curried) declarations was instructive. It wasn't something I wouldn't figure out with some head-scratching, but I feel like I can recognize the equivalence more intuitively now which will be useful in code reviews. There is so much in this chapter that it's tricky to pick out the best parts, but I think the point-free explanation and exercises stand out as really distinctly valuable. I could do point-free before, but I feel like I get the type errors from mistakes better now and that I can more frequently get a point-free construction right on the first try. As far as big personal gains from this chapter for me, I'd have to say that the guards and guard exercises really helped me make effective use of those techniques.
Recursion was an interesting chapter. Having been through the process a few times I find learning recursion almost pointless because I know that folds are where I should be reaching. However, realizing that this book isn't for experienced Haskellers, but for new ones this chapter is essential. The example algorithms explored as well as the clear presentation of the consequences of bad base cases. The exercises in this chapter were somewhat mind-bending, but not an uncomfortable reach from the material. I feel like this chapter, particularly its coverage of base cases, was a very useful preparation for the challenges of folding lists. In the spirit of iterative deepening the exercises in this chapter make significant use of concepts from the functional patterns and type classes chapters to help cement those topics on the way.
The lists chapter went deeper than I expected. Very thankfully it focused on lists as computational structures as well as data structures. Too often I find the material on Haskell teaching lists focuses on their use as data structures without considering the computational aspects. This chapter gives us a taste of Haskell's non-strict evaluation and as a result I now actually understand weak head normal form (WHNF) which is a topic where intuition had eluded me. It's actually very simple. The explanation of spine-structure of data constructors and the inherent recursiveness of lists was very well presented as well. As with all other chapters so far the exercises throughout and at chapter end were well-paced to the material. The discussion of spines in the previous chapter really comes home in explaining fold catamorphisms as deconstructors.
Folding lists. Well, I must say, this was a treat. I can't imagine the cortortions Julie and Chris must have gone through to get the topic and the exercises for folds into this form, but it's impressive. Getting an intuition about folds is incredibly valuable given their generality, but is also incredibly elusive. The brevity of this chapter is one of the biggest surprises here. I did find the exercise reimplementing factorial with scanl extremely difficult. However, setting that aside I was able to easily get the foldr-based definition of map which many other books considered to be quite advanced. Thankfully Chris and Julie recognize understanding the relationship of fold and map as not just fundamental, but within reach and important as a stepping stone in the reader's learning path. I was reaching for both point free and total functions in my answers to the chapter exercises, but doing that for 9-12 without contortions eluded me.
Through chapter 10 Haskell Programming from First Principles is holding strong with correct, runnable examples and exercises drawn clearly from supporting material. Still a strong recommendation without hesitation from me and again, with insights worth the price even for the first five chapters let alone the ten I've now completed.