Rohit Sharma
Rohit Sharma

Reputation: 6500

Pattern matching expects round braces for non empty list and not square brackets

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

Answers (2)

mb14
mb14

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

sepp2k
sepp2k

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

Related Questions