使用uncurry函数的特定类型推断

时间:2011-02-15 01:04:53

标签: haskell types ghc monomorphism-restriction

我一直在玩GHCi中的uncurry功能,而且我发现了一些我根本无法获得的功能。当我将uncurry应用于(+)函数并将其绑定到某个变量(如下面的代码中)时,编译器会将其类型推断为特定于Integer

Prelude> let add = uncurry (+)
Prelude> :t add
add :: (Integer, Integer) -> Integer

但是,当询问下面表达式的类型时,我得到(我期望的)正确的结果:

Prelude> :t uncurry (+)
uncurry (+) :: (Num a) => (a, a) -> a

会导致什么?是GHCi特有的吗?

同样适用于let add' = (+)

注意:我无法使用已编译的文件重现该文件

2 个答案:

答案 0 :(得分:21)

这与ghci无关。这是单形态限制令人恼火。如果您尝试编译以下文件:

add = uncurry (+)
main = do
    print $ add (1,2 :: Int)
    print $ add (1,2 :: Double)

您将收到错误消息。如果你展开:

main = do
    print $ uncurry (+) (1,2 :: Int)
    print $ uncurry (+) (1,2 :: Double)

正如所料,一切都很好。单态限制拒绝制作“看起来像一个值”的东西(即在equals的左侧没有参数定义)类型多态,因为这会破坏通常会发生的缓存。例如

foo :: Integer
foo = expensive computation

bar :: (Num a) => a
bar = expensive computation
保证

foo只计算一次(好吧,至少在GHC中),而每次提到时都计算bar。单态约束试图通过默认为前者来拯救你,使其成为你想要的东西。

如果您仅使用该功能一次(或始终使用相同类型),则类型推断将负责为您推断正确的类型。在那种情况下,ghci通过更快的猜测做了一些稍微不同的事情。但是在两种不同的类型中使用它会显示正在发生的事情。

如有疑问,请使用类型签名(或使用{-# LANGUAGE NoMonomorphismRestriction #-}关闭可怜的东西)。

答案 1 :(得分:4)

ghci扩展违约规则涉及到魔力。基本上,除其他外,Num约束默认为Integer和Floating约束为Double,否则会出现错误(在这种情况下,由于邪恶的单态限制)。