我想知道为什么: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的类型在第一种情况下是多态而在第二种情况下不是多态这一事实有关吗?我想知道内部是怎么回事。
发布于 2014-02-03 05:52:31
其要点是,对于多态xs,它具有一种形式
xs :: Num a => [a]引擎盖下的类型类实际上只是函数,它们采取额外的参数,GHC自动填充包含类型类函数记录的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 intSmashhttps://stackoverflow.com/questions/21518584
复制相似问题