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

How function signature matches requested types

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

foldMap (+3) (Just 5) :: Sum Int

产生结果

Sum {getSum = 8}

现在,foldMap 的类型是

foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m

并且 foldMap 使用的函数的类型签名与使用的函数 (+3) 的签名不匹配:

(+3) :: Num a => a -> a

f :: Monoid m => a -> m

如果我也尝试这样:

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  
....

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

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

简而言之:由于 instance Num a => Num (Sum a) 成立,您的 5 被视为 Sum Int

假设 aNum 类型,Sum a 也是 Num 类型。事实上,在 documentation 中我们看到:

Num a => Num (Sum a)

现在 Num 类型 n 有一个函数 fromInteger :: Integer -> n 可以将 Integer 转换为该数字类型 n。这个想法是,如果你这样写 5,你就隐含地写了类似 fromInteger 5.

的东西

通过写作

foldMap (+3) (Just 5) :: Sum Int

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 Int。因此,您编写的 5 被解释为 Sum 53.

也是如此

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

foldMap (+ (Sum 3)) (Just (Sum 5)) :: Sum Int

foldMap 会将结构的每个元素映射到一个幺半群(好吧,它已经是一个幺半群了,但无论如何它都会用 3 增加它们),然后执行折叠。所以这意味着我们写了类似的东西:

(+ (Sum 3)) (Sum 5) <> mempty

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

(+ (Sum 3)) (Sum 5) <> (Sum 0)

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

(+ (Sum 3)) (Sum 5) + (Sum 0)

可以计算为:

(Sum 5 + Sum 3) + Sum 0

或:

Sum 8