Review: Beginning Haskell
Saturday, 26th April, 2014
“Beginning Haskell: A Project-Based Approach”
Alejandro Serrano Mena
This book could have been very good: the author has the enthusiasm, the knowledge, and the focus. Unfortunately he has been very very badly let down by his publisher. As it is, the book is almost unbelievably horrible to try and read.
The comments below are based only on the first four chapters, which was as much as I could stomach. The contents of the remainder look interesting, so I may read on, … but I don’t really think I shall.
The book has all the usual dysfluencies, typos, inaccuracies, errors, which we have become used to in programming language publishing, but very thick and fast.
As well as the author, the book boasts a Lead Editor, an Editorial Board (of twenty people), a Coordinating (sic) Editor, a Copy Editor, an Indexer, and a Technical Reviewer (who is so important he warrants a photograph). That’s at least twenty five people “helping” the author. The editing and indexing in the book is so awful, and the accuracy of the technical content so variable, that I can’t imagine what any of them did for their money. The book could hardly have been worse if they’d conspired together to wreck it on purpose.
The index was actually useless. Of the five terms I looked up, *none* were in the index: case, fold, map, monoid, set.
Most pages are cluttered with dysfluent English, grammatical mistakes and typos. These are so thick they make the text quite difficult to read. Each textual error trips up the reader’s eye. It’s like walking along a street when the pavement is covered in dogshit: you can’t enjoy the scenery, you can’t think about where you’re going, all you can do is pick your way through the shit.
Worst are the code-related errors, some of which beggar belief. Code which is not Haskell:
let name = match companyName client of Just n -> n
As far as I know “match” is not a Haskell keyword. The book does not disabuse me of that impression. Neither does ghci.
There’s code that will not compile, or doesn’t do what the text says it does (in one case the code does the exact opposite of what the text claims it does).
Page 58 has a “wonderful” code example which manages not only to be inconsistent with the text, but also inconsistent with itself. It manages to do this in three lines of code!
The text says the code imports filter and reverse; the code actually imports permutations and subsequence; but the code calls (i.e., expects to have been imported) filter and permutations.
Twenty five editors. And the book has a full page dedicated to praising the Technical Reviewer.
All-in-all reading this book was an unpleasant, even nauseating, experience. Because of the book’s good points (see below) I persevered, and worked through many of the exercises.
The last straw was exercise 4-3 (p. 89).
Earlier the book had introduced a data type
Client i, where
i is a polymorphous type used as an id (p. 49), and where client can be one of three subtypes (Government, Company or Individual). Exercise 4-3 is to write a function that takes a list of Clients and returns a map from these subtypes to sets of clients, or:
classifyClients :: [Client Integer] -> Map ClientKind (Set (Client Integer))
The exercise has two parts, each suggesting an alternative implementation, and then says:
It’s interesting that you create a very large client list and run the two implementations to compare which one behaves better in speed.
Compare how exactly? Later (p. 122), we are told about how to build a cabal project with profiling options that will profile a Main module.
So let’s just forget about comparison for now and write these two functions.
It turns out that
Set (Client Integer) will not work:
*Main> let cs = S.fromList [Gov 1, Gov 2, Edu 3, Edu 4, Ind 5, Ind 6] :28:11: No instance for (Ord (Client i0)) arising from a use of `S.fromList' Possible fix: add an instance declaration for (Ord (Client i0)) In the expression: S.fromList [Gov 1, Gov 2, Edu 3, Edu 4, ....] In an equation for `cs': cs = S.fromList [Gov 1, Gov 2, Edu 3, ....]
Needless to say none of Ord, Set or deriving are in the index, and nothing in the text on Sets indicates that there is a constraint that members of sets must be of type/class Ord. Type classes, including Ord and Eq and deriving, are introduced a bit further on (p. 97). The Client type is defined with just deriving Show (p. 49).
I could have taken this as an extra challenge — interpret those error messages, fix the data type: I did do both those things after all — and in another book I would have. With this book though, I decided it was just more dogshit, and I decided I just didn’t care any more.
What a horrible book.
All of the textual errors I encountered would have been picked up by an averagely competent editor doing their job. Similarly all of the code errors would have been picked up on a first sweep by an editor with a passing acquaintance with programming languages in general.
The bad points of the book, which make it unusable I think, and certainly unrecommendable, are all down to the publisher and the editorial team.
On the other hand, the author has written something which could have been a very good book, and could certainly have been the best practical introduction to Haskell.
The author’s enthusiasm is palpable and infectious. As well as the exercises, I was motivated to try out code from the text (admittedly, often just to see if it was correct Haskell) and some variations of my own. e.g., inspired by a haskell function for 3x + 7(x + 2) (p. 57), I tried one for ax^2 + bx + c:
dup x = (x,x) f *** g = \ (x,y) -> (f x, g y) abc a b c = (uncurry (+)) . (((*a) . (^2)) *** ((+c) . (*b))) . dup *Main> let f = abc 1 2 3 *Main> f 5 38 *Main> f 10 123 *Main> let f = abc 3 1 2 *Main> f 5 82 *Main> f 10 312
The author is ambitious and wide-ranging — covering parsing, parallelism, DSLs, Idris(!); the GHCi ecosystem including things like GHC extensions, cabal, Hoogle, Haddock, HUnit, and more — but by tieing everything to a concrete project (the usual web app) keeps things focussed, keeps the pace up, and introduces advanced topics in a natural way.
If this book had the appearance of having been edited competently, it could have become the definitive practical introduction to Haskell: the kind of book a programmer could use for self-study, or a technical manager could give to starting team members.
As it is, I would be embarrassed to recommend this to anybody.