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

时间:2018-08-08 12:32:25

标签: haskell type-inference

我试图了解其工作原理;在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

vs

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,然后可以折叠成单个值。

我假设编译器推断出应该是什么类型(在上面明确声明的那一行中),但是我不明白的是编译器如何“调整”函数的类型签名(+3),以便第一行进行编译? / p>

1 个答案:

答案 0 :(得分:6)

简而言之:由于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 Intt ~ 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会将结构的每个元素映射到一个Monoid(好了,它已经是一个Monoid,但是无论如何它将用3对其进行递增),然后执行折叠。所以这意味着我们写了类似的东西:

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

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

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

(<>)的{​​{1}}是Sum,因此表示表达式可以归结为:

(+)

可以评估为:

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

或:

(Sum 5 + Sum 3) + Sum 0