Reputation: 6500
In Haskell why pattern matching expects list to have round braces but not square braces when it is not empty? Why does it not follow the same convention when it tries to pattern match with empty list [] (square braces). Shouldn't the round braces reserved exclusively for tuples?
For example - below does not work
third :: Integral a => [a] -> a
third xs = case xs of
[] -> 0
[_:_:x:_] -> x
otherwise -> 0
But this works
third :: Integral a => [a] -> a
third xs = case xs of
[] -> 0
(_:_:x:_) -> x
otherwise -> 0
Upvotes: 3
Views: 645
Reputation: 22616
There is actually to way to write a list
[1, 2, 3]
Or
1:2:3:[]
(Note the :[]
at the end). The first one is the traditional way of writing a list but is actually just a shortcut to write the second one. :
denotes the cons operator and []
denotes an empty list (which appears to be the same as []in the first version).
3:[]means , take 3 and prepend it to the empty list (which is then equivalent to [3]).
2:3:[]means : prepend 2 to the previous list (which is also equivalent to 2:[3]
. And finally 1:2:3:[]
is equivalent to 1:[2,3]
. So
[1, 2, 3]
1:[2,3]
1:2:[3]
1:2:3:[]
are equivalent. However [1:2:3:[]]
is equivalent to [[1,2,3]]
not [1,2,3]
.
So, when you pattern match on (x:_)
, you are saying : I want a list starting with x
and I don't care of it's tail (therefore it can be ANY length). When you write [x:_]
, you are actually writting [(x:_)]
, which means, I want a list of ONE elements, this element start with x
. This could be correct, but the list you are pattern matching on is not a list of a but a list of list of a ([[a]]
) which doesn't match your type signature.
Upvotes: 8
Reputation: 370387
The list pattern [p1, ..., pn]
matches an n-element list where each element matches the patterns p1
through pn
respectively. The pattern [p]
is a list pattern with only one element, so it matches a list with exactly one element that matches the pattern p
. So [_:_:x:_]
matches a list containing exactly one element and that element must be a list matching the pattern _:_:x:_
.
So why doesn't the same logic apply to (p)
and tuples? That is, why doesn't (_:_:x:_)
match a one-element tuple that contains a list? Because there's no such thing as a one-element tuple. Parentheses in Haskell are overloaded in a way: When they contain a comma, they denote a tuple; if they contain nothing (()
), they denote the unit value; otherwise they're just used for grouping.
So the pattern (_:_:x:_)
just matches the pattern _:_:x:_
. The parentheses are usually just used to avoid ambiguity (f x:y = ...
would be interpreted as (f x):y = ...
, not f (x:y) =...
), but in this case they're actually redundant. You could just write:
third xs = case xs of
[] -> 0
_:_:x:_ -> x
otherwise -> 0
Upvotes: 6