While learning Haskell I found something which puzzled me.
I don't understand why this code is valid:
Prelude> [y | y <- "a", y <- ["a"]]
["a"]
I tried to change to an explicit [Char]
and got the same result (which makes sense):
Prelude> [y | y <- ['a'], y <- ["a"]]
["a"]
Surprisingly this is valid too :
Prelude> [y | y <- "a", y <- [["a"]]]
[["a"]]
[EDIT] the error given is not related to the same fact :
This on the contrary is invalid as I would expect:
Prelude> [y | y <- 'a', y <- ['a']]
<interactive>:12:11: error:
* Couldn't match expected type `[t0]' with actual type `Char'
* In the expression: 'a'
In a stmt of a list comprehension: y <- 'a'
In the expression: [y | y <- 'a', y <- ['a']]
[y | y <- 'a']
is invalid because 'a' is not a list.
[/EDIT]
I thought it was some usual mess caused by String
vs Char
but definitely not:
Prelude> [y | y <- [1], y <- [[2]]]
[[2]]
For the record I'm using GHCi version 8.2.2 and Arch Linux.
Turn on warnings! You should see that the first y
is being shadowed by the second one.
It is somehow similar to
let y = True
in let y = "a"
in y
where the first definition is overshadowed, as if it were
let _ = True
in let y = "a"
in y
or even, removing the shadowed binding,
let y = "a"
in y
Similarly, a list comprehension such as
[y | y <- "a", y <- ["a"]]
evaluates to the same result as
[y | _ <- "a", y <- ["a"]]
-- or, if you prefer
[y | x <- "a", y <- ["a"]]
Note that, unlike the let
above, in list comprehensions we can not simply remove the overshadowed binding y <- ...
. For instance,
[y | y <- [1,2], y <- [3,4]]
produces [3,4,3,4]
, unlike [y | y <- [3,4]]
.
Here you can see the produced warning for each examples :
Prelude> :set -Wall
Prelude> [y | y <- "a", y <- ["a"]]
<interactive>:41:6: warning: [-Wunused-matches]
Defined but not used: `y'
<interactive>:41:16: warning: [-Wname-shadowing]
This binding for `y' shadows the existing binding
bound at <interactive>:41:6
["a"]
Prelude> [y | x <- "a", y <- ["a"]]
<interactive>:47:6: warning: [-Wunused-matches]
Defined but not used: `x'
["a"]
-- no warning here
Prelude> [y | _ <- "a", y <- ["a"]]
["a"]
Prelude> [y | y <- [1,2] , y <- [3,4]]
<interactive>:49:1: warning: [-Wtype-defaults]
* Defaulting the following constraints to type `Integer'
(Show a0) arising from a use of `print' at <interactive>:49:1-29
(Num a0) arising from a use of `it' at <interactive>:49:1-29
* In a stmt of an interactive GHCi command: print it
<interactive>:49:6: warning: [-Wunused-matches]
Defined but not used: `y'
<interactive>:49:12: warning: [-Wtype-defaults]
* Defaulting the following constraint to type `Integer'
Num t0 arising from the literal `1'
* In the expression: 1
In the expression: [1, 2]
In a stmt of a list comprehension: y <- [1, 2]
<interactive>:49:12: warning: [-Wtype-defaults]
* Defaulting the following constraint to type `Integer'
Num t0 arising from the literal `1'
* In the expression: 1
In the expression: [1, 2]
In a stmt of a list comprehension: y <- [1, 2]
<interactive>:49:19: warning: [-Wname-shadowing]
This binding for `y' shadows the existing binding
bound at <interactive>:49:6
[3,4,3,4]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With