:多态值的冲刺?

我想知道为什么: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 。 这是否与第一种情况下的xstypes是多态有关,而不是第二种情况呢? 我想知道内部发生了什么。

要点是,与多态xs它有一个forms的types

 xs :: Num a => [a] 

引擎盖下的types实际上只是函数,他们需要一个额外的参数,GHC自动填充包含typeclasses函数的logging。 所以你可以认为xs是types的

 xs :: NumDict a -> [a] 

所以当你跑步

 Prelude> length xs 

它必须为aselect一些值,并find相应的NumDict值。 IIRC它会用Integer填充它,所以你实际上正在调用一个函数,并检查结果列表的长度。

当你那么:sprint xs ,你再一次填充这个参数,这次用一个新鲜的typesvariables。 但重要的是,你得到了一个完全不同的列表,你给它一个不同的NumDict所以当你以前调用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 

这实际上是什么types的types是在引擎盖下,GHC会自动填写第一个Smash a我们Smash a论据。 现在你的第一个例子就像join ,我们不能做任何假设输出将是什么,因为我们将其应用于不同的types,但你的第二个例子更像

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