Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why [x, y, _] isn't allowed in pattern matching

Here is my code:

tell :: (Show a) => [a] -> String  
tell [] = "The list is empty"  
tell (x:[]) = "The list has one element: " ++ show x  
tell (x:y:[]) = "The list has two elements: " ++ show x ++ " and " ++ show y  
tell (x:y:_) = "Other" 

in the last line why can't I change (x:y:_) to [x, y, _]?

And what is the global meaning of _?

like image 743
Valentin Grigorev Avatar asked Nov 28 '22 05:11

Valentin Grigorev


2 Answers

You can change (x : y : _) to [x, y, _], but it won't mean the same thing. [x, y, _] is equivalent to (x : y : _ : []), i.e. a list of exactly three elements (the first two of which are bound to x and y).

Similarly, x : y is a list whose head (first element) is x and whose tail (remaining elements) is y, but [x, y] is a list of exactly two elements.

I'm not sure what you mean by "global meaning", but _ is a wildcard pattern that matches any value, but doesn't bind it to a name.

like image 32
melpomene Avatar answered Dec 06 '22 07:12

melpomene


in last line why I can't change (x:y:_) to [x, y, _]

They have different meanings:

  • [x, y, _] refers to a list with three elements; the first element is bound to x, the second is bound to y, and the third element is not bound to any name. It's equivalent to (x:y:_:[]).
  • By contrast, (x:y:_) refers to a list with at least two elements, since : is a constructor used to join the first element of a list with the rest of the list; in the above pattern, the first element is bound to x, the second is bound to y, and the rest of the list (which may or may not be empty) is not bound to any name.

And what the global meaning of _?

You shouldn’t really ask two questions in one post, but it’s relevant here, so: _ is just a placeholder when you want to match a particular pattern, but not give it a name. So in the above examples:

  • [x,y,z] will bind each element of a three-element list to the names x, y and z respectively (exactly equivalent to (x:y:z:[])). When you replace z with _, it still matches a three-element list, but does not give the last element a name.
  • (x:y:z) will bind the first two elements of an at-least-two-element list to the names x and y, then binds the rest of the list to z. When you replace z with _, it still matches a list of at least two elements, but does not give the rest of the list a name.
like image 149
bradrn Avatar answered Dec 06 '22 07:12

bradrn