为什么Haskell没有概括某些函数

me2*_*me2 3 haskell types

我在文件中有以下内容:

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

在编译时,我得到以下内容:

:t macd
macd :: [Integer] -> [Integer]
Run Code Online (Sandbox Code Playgroud)

然而,

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

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

Dan*_*zer 10

这是单态限制.

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

f = term
Run Code Online (Sandbox Code Playgroud)

但是,如果它是一个功能绑定,例如

f a ... = term
Run Code Online (Sandbox Code Playgroud)

然后它被推广.我已经回答了这个问题,我在博文中写了一个更完整的例子


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

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

comp计算多少次?如果我们自动推断一般类型,它可以计算两次.但是如果你写这样的东西想要有类型Num a => (a, a)或类似的东西,这可能会让你感到惊讶.

额外的计算是因为在核心土地之类的东西

foo :: Num a => a
Run Code Online (Sandbox Code Playgroud)

变成更像的东西

 foo :: NumDict -> a -- NumDict has the appropriate functions for + - etc
                     -- for our a
Run Code Online (Sandbox Code Playgroud)

一个功能.由于foo一般类型是(Num a, Num b) => (a, b)除非GHC可以证明在两种情况下得到的NumDicts comp是相同的,它不能分享结果comp

  • 作为一个元音符,确实应该有一个明确的"这就是单态限制是什么"的问题,我们可以链接到这里 (3认同)
  • @ me2是的,或者只是添加类型签名:)通常这就是我推荐的.它对人类和编译器很有帮助 (3认同)