如何正确使用 seq In list comprehension?

How to properly use seq In list comprehension?

我试图在列表推导中使用 seq 来强制对生成的元素求值,但是 :sprint 告诉我我的列表实际上没有被求值。例如:

Prelude> let foo a b = a + b
Prelude> let bar c = c + 1
Prelude> let lst = [bar $ foo x y | y <- [0..9], x <- [0..9]]
Prelude> :sprint lst
lst = _
Prelude> seq lst ()
()
Prelude> :sprint lst
lst = _

但其他人的 map 似乎工作正常:

Prelude> let xs = map (+1) [1..10] :: [Int]
Prelude> :sprint xs
xs = _
Prelude> seq xs ()
()
Prelude> :sprint xs
xs = _ : _

为什么我的 seq 不工作?

你没有给 lst 一个具体的类型所以对于 ghci 它是一个新的 instance/value 每次你使用它(GHCi 会选择一个 默认 键入它)

如果您没有更改任何内容,您甚至应该看到这样的警告:

<interactive>:19:1: warning: [-Wtype-defaults]
    • Defaulting the following constraints to type ‘Integer’
        (Show a0) arising from a use of ‘print’ at <interactive>:19:1-10
        (Num a0) arising from a use of ‘it’ at <interactive>:19:1-10
        (Enum a0) arising from a use of ‘it’ at <interactive>:19:1-10
    • In a stmt of an interactive GHCi command: print it

添加 :: [Int] 它应该可以工作:

> let foo a b = a + b
> let bar c = c + 1
> let lst = [bar $ foo x y | y <- [0..9], x <- [0..9]] :: [Int]
> :sprint lst
lst = _
> seq lst ()
()
> :sprint lst
lst = _ : _

我喜欢将 泛型类型 视为具有额外的 不可见 参数:类型参数的类型 - 所以它更像是一个函数然后是一个值;)(当然在现实中它并不完全像这样,但它帮助我解决了这样的问题)


编辑 正如@dfeuer 指出的那样,关于 parameters/invisible-functions 的评论可能具有误导性甚至是错误的。

遗憾的是,我不能声称真的知道 GHCi 如何处理这个问题(当我找到来源时我会很乐意添加一些东西)但到目前为止我的直觉是,GHCi does/cannot 创造了一个价值直到所有dictionaries 类型-class 约束是已知的 - 所以如果没有约束它可以并且将创建值(在运行时没有类型所以这没问题) .

在上面的示例中,隐式 Num 约束(019+)要求这样一个 相关类型的 Num 实例的字典