3

我在一个文件中有以下内容:

import Control.Monad
ema a = scanl1 $ \m n -> (1-a)*m + a*n
macd  = ema 9 . uncurry (zipWith (-)) . liftM2 (,) (ema 26) (ema 12)

编译时,我得到以下信息:

:t macd
macd :: [Integer] -> [Integer]

然而,

:t ema 9 . uncurry (zipWith (-)) . liftM2 (,) (ema 26) (ema 12)
ema 9 . uncurry (zipWith (-)) . liftM2 (,) (ema 26) (ema 12)
  :: Num a => [a] -> [a]

那么,为什么在更受限制的类型中存在差异macd呢?

4

1 回答 1

10

这就是单态性限制。

要点是,当您有一个受约束的类型变量时,如果它绑定到单个标识符,Haskell 将不会泛化

f = term

但是,如果它是一个函数绑定,例如

f a ... = term

然后是泛化的。我已经回答了这个问题,所以我在博客文章中写了一个更完整的例子


至于为什么我们有单态限制,

-- let's say comp has the type [Num a => a]
foo = (comp, comp)
  where comp = super_expensive_computation

comp会计算多少次?如果我们自动推断一般类型,它可以计算两次。但是,如果您编写类似这样的内容打算使用该类型Num a => (a, a)或类似内容,这可能会让您感到惊讶。

发生额外的计算是因为在 Core Land 中类似于

foo :: Num a => a

变成更像

 foo :: NumDict -> a -- NumDict has the appropriate functions for + - etc
                     -- for our a

一个函数。由于foos 的一般类型是(Num a, Num b) => (a, b)除非 GHC 可以证明在两种情况下得到的NumDictscomp是相同的,它不能共享结​​果comp

于 2013-10-08T17:34:49.890 回答