Reputation: 34353
The following reverse'
function has type Eq t => [t] -> [t]
:
reverse' list | list == [] = []
| otherwise = (reverse' listTail) ++ [listHead]
where (listHead : listTail) = list
Why must the elements of the list be members of the typeclass Eq
? I'm not comparing the elements for equality but the list they are contained in.
In my intuition, the list of t
must be equatable, but t
itself doesn't.
Upvotes: 1
Views: 293
Reputation: 53881
This is because we can only compare lists in general for equality if we can compare their elements for equality. That is, in the general case there's no real way to explain [a, b, c] == [d, e, f]
unless we can explain a == d
.
This is reflected in the type of (==)
on lists which after all works for both your case and the more generalized one:
(==) :: (Eq a) => [a] -> [a] -> Bool
However you don't want to compare a list of equality with another list really, you just want to check whether a list is empty and so
null :: [a] -> Bool
is a far better choice for you. And it doesn't have that equality constraint because it just uses pattern matching on the structure of the list, something that never requires a type class constraint.
null :: [a] -> Bool
null [] = True
null (_ : _) = False
Even better in your case would be to just do the pattern matching yourself, after all, you're already right by a pattern!
reverse' [] = []
reverse' (listHead : listTail) = (reverse' listTail) ++ [listHead]
This is much closer to idiomatic Haskell because verifying that it doesn't crash can be done trivially by the compiler, we've exhaustively covered all cases in a way that it can check. In your version, to verify that the code would work we had to trace the two paths through the code and ensure an empty list would never end up in the branch where we had done that pattern match. This is only a small problem right now, but it will creep up in difficulty very quickly.
Upvotes: 8
Reputation: 105886
Because (==) :: Eq a => a -> a -> Bool
only works for instances of Eq
, and []
is only an instance of Eq
if its elements are an instance of Eq
:
instance (Eq a) => Eq [a] where
...
Instead, use null :: [a] -> Bool
or pattern matching to check whether a list is empty:
reverse' [] = []
reverse' xs = ...
Upvotes: 5