Reputation: 421
Why does the following Haskell script not work as expected?
find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (k,v) <- t]
Given find 'b' [('a',1),('b',2),('c',3),('b',4)]
, the interpreter returns [1,2,3,4]
instead of [2,4]
. The introduction of a new variable, below called u
, is necessary to get this to work:
find :: Eq a => a -> [(a,b)] -> [b]
find k t = [v | (u,v) <- t, k == u]
Does anyone know why the first variant does not produce the desired result?
Upvotes: 5
Views: 876
Reputation: 138
You can only pattern match on literals and constructors.
You can't match on variables.
Read more here.
That being said, you may be interested in view patterns.
Upvotes: 3
Reputation: 139058
From the Haskell 98 Report:
As usual, bindings in list comprehensions can shadow those in outer scopes; for example:
[ x | x <- x, x <- x ] = [ z | y <- x, z <- y]
One other point: if you compile with -Wall
(or specifically with -fwarn-name-shadowing
) you'll get the following warning:
Warning: This binding for `k' shadows the existing binding
bound at Shadowing.hs:4:5
Using -Wall
is usually a good idea—it will often highlight what's going on in potentially confusing situations like this.
Upvotes: 14
Reputation: 229854
The pattern match (k,v) <- t
in the first example creates two new local variables v
and k
that are populated with the contents of the tuple t
. The pattern match doesn't compare the contents of t
against the already existing variable k
, it creates a new variable k
(which hides the outer one).
Generally there is never any "variable substitution" happening in a pattern, any variable names in a pattern always create new local variables.
Upvotes: 11