
The definition last [] = [] was a bad move. Warnings about unhandled alternatives are only that, WARNINGS. Something like this is quite definitely wrong. We want last [1,2,3] ===> 3 but last [] = [] says that last can only return lists. It's OK to say "this is not defined". It's OK to say "this is an error case". It's not OK to make stuff up that does not fit. last [] = undefined last (x:xs) = last' x xs or last [] = error "last []" last (x:xs) = last' x xs let you assure the compiler (and your readers) that you *have* considered this case; you didn't just forget about it. They also do not constrain the result type in any way, so they don't interfere with the rest of the definition. The meaning of last' x xs is "last' x xs is the last element of [x]++xs" and you can figure that out for yourself with a simple case analysis on xs. A hint on reading exercises in functional programming books: "make a function F that ..." almost NEVER means "make a function F that ... without even thinking about introducing any helper functions." When defining last, introducing last' is OK. You can make it local if you want: last (x:xs) = last' x xs where last' x (y:ys) = ... last' x [] = ... last [] = error "last []" although you don't need to.