Yet Another Haskell Tutorial/Errata

Haskell
Yet Another Haskell Tutorial
Preamble
Introduction
Getting Started
Language Basics (Solutions)
Type Basics (Solutions)
IO (Solutions)
Modules (Solutions)
Advanced Language (Solutions)
Advanced Types (Solutions)
Monads (Solutions)
Advanced IO
Recursion
Complexity

This page contains a list of errata which have been discovered so far in the PDF version of YAHT (some of these may have already been corrected in the online HTML version - (imported)).

  • Exercise 3.1: "We’ve seen that multiplication binds more tightly than division." - as far as I'm concerned, multiplication and division have the same priority, so they bind equally tightly. Maybe you meant addition vs multiplication or multiplication vs exponentiation? I see it has been fixed in the online version already.
  • There is a bug in the solution to Exercise 7.1 on page 79, under "7.3 Partial Application" (see Advanced Language: Partial Application for the corresponding HTML version (which has already been corrected)), for which the exercise is stated as follows:


Exercises

Convert the following functions into point-free style, if possible.

[...]

func5 f l = foldr (\x y -> f (y,x)) 0 l
  • On page 81, text states

"we create a value, call it x, which has value Red. We then apply this to colorToRGB. We check to see if we can “match” x against Red. This match fails because according to the definition of Eq Color, Red is not equal to Yellow."

Clearly, the premise is wrong, the initial value x should be 'Yellow' in order for the rest of the paragraph to make sense.


  • According to the page 172 of the PDF file, the solution is stated as follows:
[...]

func5 = foldr (uncurry $ flip f) 0

However, as pointed out by Michael Mossey on the Haskell-Beginners mailing list, that solution is actually incorrect.

Here is the correct solution:

[...]

func5 = flip foldr 0 . flip . curry 

As a sidenote, Daniel Fischer has provided a succinct way of verifying correctness of the solutions, using types, as follows:


A simple way to check for sanity of the results is:

Example:

Prelude> :t flip foldr 0 . flip. curry
flip foldr 0 . flip. curry :: (Num c) => ((c, b) -> c) -> [b] -> c

Prelude> :t \f list -> foldr (\x y -> f (y,x)) 0 list
\f list -> foldr (\x y -> f (y,x)) 0 list :: (Num b) =>
                                             ((b, a) -> b) -> [a] -> b

Prelude> :t \f -> foldr (uncurry $ flip f) 0
\f -> foldr (uncurry $ flip f) 0 :: (Num b1) =>
                                    (b -> a -> b1 -> b1) -> [(a, b)] -> b1

So you see that your result has the correct type, while Hal's hasn't.


In the above-mentioned description, the first pair of two lines show that the type of

flip foldr 0 . flip. curry

(i.e., the solution to verify) is

(Num c) => ((c, b) -> c) -> [b] -> c

The second pair of two lines show that the type of

\f list -> foldr (\x y -> f (y,x)) 0 list

(i.e., essentially the expression given in the exercise, which was f l = foldr (\x y -> f (y,x)) 0 l) is also

(Num b) => ((b, a) -> b) -> [a] -> b

(Note that this is the same type as above, only written with renamed variables.)

The third pair of two lines show that the type of

\f -> foldr (uncurry $ flip f) 0

(i.e., the solution given by Hal in the PDF version of the tutorial) is

(Num b1) => (b -> a -> b1 -> b1) -> [(a, b)] -> b1

which is a different type. Hence, the solution given by Hal is incorrect.

Note

(Thanks to both Michael Mossey and Daniel Fischer for their discussion on the Haskell-Beginners mailing list regarding this issue.)

-- Benjamin L. Russell


2. Exercise 4.11:

Exercises
4.11. Test whether the CPS-style fold mimicks either of foldr and foldl. If not, where is the difference?

It does not specify the "CPS-style fold" function, so the reader should assume that the exercise is about the previously defined cfold:

cfold’ f z [] = z
cfold’ f z (x:xs) = f x z (\y -> cfold’ f y xs)
cfold f z l = cfold’ (\x t g -> f x (g t)) z l

But the solution given in YAHT is actually not about this function. In fact, this function behaves exactly as foldr. The solution is about very similar function: the only difference is in the order of arguments for the second case of cfold', namely

cfold' f z (x:xs) = f z x (\y -> cfold' f y xs)