函数签名如何匹配请求的类型

sim*_*uff 4 haskell type-inference

我试图了解这是如何工作的; 在GHCi中:

foldMap (+3) (Just 5) :: Sum Int
Run Code Online (Sandbox Code Playgroud)

产生结果

Sum {getSum = 8}
Run Code Online (Sandbox Code Playgroud)

现在,foldMap的类型是

foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
Run Code Online (Sandbox Code Playgroud)

从该类型中,foldMap使用的函数的签名与使用函数的签名(+3)不匹配:

(+3) :: Num a => a -> a
Run Code Online (Sandbox Code Playgroud)

VS

f :: Monoid m => a -> m
Run Code Online (Sandbox Code Playgroud)

如果我也尝试这样的事情:

foldMap _ (Just 5) :: Sum Int
---------------------------------------
<interactive>:113:9: error:  
* Found hole: _ :: Integer -> Sum Int  
* In the first argument of `foldMap', namely `_'  
  In the expression: foldMap _ (Just 5) :: Sum Int  
....
Run Code Online (Sandbox Code Playgroud)

这也表明期望的函数是签名的:: (Integer -> Sum Int),并且与foldMap声明中的签名一致,但与上面使用的(+3)不一致?我对foldMap的理解是它应用了将Foldable实例的每个元素转换为Monoid的函数,然后可以将其折叠成单个值.

我假设编译器推断应该是什么类型(在上面的行中明确说明)但我不明白的是编译器如何"调整"类型签名的函数(+3)以便第一行编译?

Wil*_*sem 6

简而言之:既然instance Num a => Num (Sum a)持有,你5被视为一个Sum Int.

给定a是一种Num类型,Sum a也是一种Num类型.实际上,在文档中我们看到:

Num a => Num (Sum a)
Run Code Online (Sandbox Code Playgroud)

现在,Num类型n具有fromInteger :: Integer -> n将变换Integer为该数字类型的函数n.这个想法是,如果你这样写5,你隐含地写了类似的东西fromInteger 5.

通过写作

foldMap (+3) (Just 5) :: Sum Int
Run Code Online (Sandbox Code Playgroud)

foldMap :: (Foldable f, Monoid m) => (a -> m) -> t a -> m我们因此知道,m应该是一个Sum Int,即t ~ Maybe,由于(+3) :: Num a => a -> a,这意味着m ~ a ~ Sum Int.因此,它意味着5(从Just 5)和3(从(+3))是Sum Ints.在5这样你写被解释为Sum 5.这同样适用3.

所以现在我们知道我们实际写了:

foldMap (+ (Sum 3)) (Just (Sum 5)) :: Sum Int
Run Code Online (Sandbox Code Playgroud)

foldMap将所述结构的每个元素映射到一个独异(以及它已经是一个独异,但它会增加它们与3反正),然后执行一个折叠.这意味着我们写了类似的东西:

(+ (Sum 3)) (Sum 5) <> mempty
Run Code Online (Sandbox Code Playgroud)

对于Num n => Sum n类型memptySum 0,所以这意味着我们写道:

(+ (Sum 3)) (Sum 5) <> (Sum 0)
Run Code Online (Sandbox Code Playgroud)

(<>)用于一个Sum(+),所以这意味着表达归结为:

(+ (Sum 3)) (Sum 5) + (Sum 0)
Run Code Online (Sandbox Code Playgroud)

可以评估为:

(Sum 5 + Sum 3) + Sum 0
Run Code Online (Sandbox Code Playgroud)

要么:

Sum 8
Run Code Online (Sandbox Code Playgroud)