2
votes

In prelude, head has the following signature : head :: [a] -> a which makes it unsafe on empty list, which is not good !! (head :: [a] -> Maybe a is the good way :-) )

this applies for a couple of other functions on list : last, tail, init minimum, maximum, cycle, last, init, foldl1, cycle... there are actually a lot of these calling errorEmptyList

Quoting Stephen Diehl from his website :

"Safe provides Maybe versions of many of the various partial functions (head, tail) that are shipped by default. Wrapping it up in a Maybe is widely considered the right approach and if Haskell were designed today, they would not be present."

I would love to see these unsafe functions tagged somehow with some convention at least because I don't think any of us like when an exception blows up in production :-)

What prevents the community from fixing these issues in the prelude ?

2
Backwards compatibility seems like a good reason.. besides, wouldn't you just be moving the empty-check from the calling site to the receiving site? - thebjorn
I agree it would have been a good idea to make a signature head :: Unsafe => [a] -> a, such that one can "turn off" unsafe functions, but unfortunately it is "too late", by introducing that, it would break a lot of existing code. Furthermore a lot of functions have been designed without such signature, hence it would be of "limited" use. - Willem Van Onsem
One of the main problems is that you can use unsafe functions in such a way, that the result itself is safe. For example one can use head, but if you know for sure you are dealing with a non-empty list, then this is not unsafe, so you can make a very conservative approach where you mark everything that uses unsafe functions as unsafe. But this will act like a "virus" contaminating a lot of functions that are safe. - Willem Van Onsem
@thebjorn , usually it's a good practice to unlift a Maybe/Either at the highest layer because then you have a better context to treat the issue. - Nicolas Henin

2 Answers

5
votes

The community has been fixing this issue in the custom preludes that are distributed on Hackage. But it can't fix the prelude itself, it's up to the Haskell Committee in charge. For matters of backward compatibility, it has never been fixed.

(I personally prefer Relude's approach on that matter. This prelude's head function is typed as NonEmpty a -> a.)

4
votes

The real question is why there is a function head at all. This isn't needed for working with lists. To case-separate (x:_) and [], as “safe head” would allow you, the best option is to just use pattern matching, or suitable higher-order functions / lens operators.

In practice, the only use for head is when you're in some big function, want at the head of some list xs (among many other parameters) where you have already checked that it is nonempty, e.g. because some other clause has already covered that. In that case, the safety would be redundant.

Arguably, this is still a kludge and would better be expressed with pattern-matching. But the point is, the unsafe head has at least some ugly-but-pragmatic uses, whereas a safe head would mostly add extra noise to pattern matching that needs to be done anyway.

IMO, head, tail and !! should just be deprecated, not changed. They keep tripping up beginners coming from Python etc. thinking that they need such functions, but actually this style is inherently against the grain of Haskell.