haskell - :sprint for polymorphic values?

标签 haskell ghci thunk monomorphism-restriction

我想知道为什么 :sprint 在这种情况下报告 xs = _:

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

但不是在这种情况下:

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

注意:我正在使用 -XNoMonomorphismRestriction 运行 ghci。这是否与 xs 的类型在第一种情况下是多态的但在第二种情况下不是有关?我想知道内部发生了什么。

最佳答案

要点是,对于多态 xs,它具有以下形式的类型

xs :: Num a => [a]

底层的类型类实际上只是函数,它们采用 GHC 自动填充的额外参数,其中包含类型类函数的记录。所以你可以认为 xs 具有类型

xs :: NumDict a -> [a]

所以当你运行时

Prelude> length xs

它必须为a选择一些值,并找到相应的NumDict值。 IIRC 它将用 Integer 填充它,因此您实际上是在调用函数并检查结果列表的长度。

当您使用 :sprint xs 时,您将再次填充该参数,这次使用新的类型变量。但关键是,您得到了一个完全不同的列表,您给了它一个不同的 NumDict,因此当您之前调用 length 时,它不会以任何方式强制。

这与显式单态列表非常不同,因为那里实际上只有一个列表,只有一个要强制的值,因此当您调用 length 时,它会强制它用于 xs 的所有 future 使用.

为了让这一点更清楚,请考虑代码

data Smash a = Smash { smash :: a -> a -> a }
-- ^ Think of Monoids

intSmash :: Smash Int
intSmash = Smash (+)

listSmash :: Smash [a]
listPlus = Smash (++)

join :: Smash a -> [a] -> a
join (Smash s) xs = foldl1' s xs

这实际上就是类型类的本质,GHC 会自动为我们填写第一个 Smash a 参数。现在您的第一个示例类似于 join,当我们将其应用于不同类型时,我们无法对输出进行任何假设,但您的第二个示例更像

join' :: [Int] -> Int
join' = join intSmash

关于haskell - :sprint for polymorphic values?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21518584/

相关文章:

haskell - 表示时间戳

haskell - Haskell 中 LANGUAGE 关键字的用途是什么?

haskell - Haskell 中两个不相关类型之间的情况

haskell - Haskell 中具有多个参数的新类型

list - Haskell 的 head tail init 和 last 在 GHCi

list - 是否可以在不破坏等式推理的情况下使用教堂编码?

haskell - 如何查找 Haskell 名称的包、版本、文档

dll - 导入地址表中的 Thunk 表?

c++ - 为什么需要虚拟 thunk?

ios - Swift - App store reject - 部分应用转发器以重新抽象 thunk helper