:sprint的多态值?

时间:2014-02-03 01:41:03

标签: 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 = [_,_,_,_,_,_,_,_,_,_]

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

1 个答案:

答案 0 :(得分:10)

要点是多态xs它有一种形式

xs :: Num a => [a]
引擎盖下的类型实际上只是函数,它们需要额外的参数,GHC自动填充包含类型类函数的记录。所以你可以想到xs具有类型

xs :: NumDict a -> [a]

所以当你运行

Prelude> length xs

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

当你然后:sprint xs时,你再一次用一个新的类型变量来填充那个参数。但关键是你得到了一个完全不同的列表,你给它一个不同的NumDict所以当你之前调用length时,它不会以任何方式强迫它。

这与明确的单态列表非常不同,因为那里只有一个列表,只有一个值强制这样,当你调用length时,它强制它用于xs的所有未来用途。

为了使这一点更清晰,请考虑代码

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