为什么列表理解接受混合的 `[Char]` 和 `[[Char]]` 而不会在 Haskell 中出错?

Why does a list comprehension accept mixed `[Char]` and `[[Char]]` without error in Haskell?

在学习Haskell的过程中,我发现了一些令我困惑的事情。

我不明白为什么此代码有效:

Prelude> [y | y <- "a", y <- ["a"]]
["a"]

我尝试更改为显式 [Char] 并得到相同的结果(这是有道理的):

Prelude> [y | y <- ['a'], y <- ["a"]]
["a"]

令人惊讶的是,这也是有效的:

Prelude> [y | y <- "a", y <- [["a"]]]
[["a"]]

[编辑] 给出的错误与同一事实无关:

正如我所料,这恰恰相反:

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'] 无效,因为 'a' 不是列表。

[/编辑]

我认为这是 StringChar 造成的一些常见混乱,但绝对不是:

Prelude> [y | y <- [1], y <- [[2]]]
[[2]]

郑重声明,我使用的是 GHCi 8.2.2 版和 Arch Linux。

打开警告!您应该看到第一个 y 被第二个覆盖。

有点类似于

let y = True
in let y = "a"
in y

第一个定义被遮盖了,就好像它是

let _ = True
in let y = "a"
in y

甚至,删除阴影绑定,

let y = "a"
in y

类似地,列表理解如

[y | y <- "a", y <- ["a"]]

计算结果与

相同
[y | _ <- "a", y <- ["a"]]
-- or, if you prefer
[y | x <- "a", y <- ["a"]]

请注意,与上面的 let 不同,在列表推导中,我们不能简单地删除隐藏的绑定 y <- ...。例如,

[y | y <- [1,2], y <- [3,4]]

产生 [3,4,3,4],不同于 [y | y <- [3,4]]

在这里您可以看到每个示例生成的警告:

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]