我试图了解这是如何工作的;在 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 然后可以折叠成单个值。我假设编译器推断应该是什么类型(在上面的行中明确说明)但我不明白的是编译器如何“调整”函数(+3)的类型签名以便第一行编译?
最佳答案
总之 : 自 instance Num a => Num (Sum a)
持有,您的 5
被视为 Sum Int
.
给定 a
是 Num
类型, 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
s。 5
您写的内容因此被解释为 Sum 5
.这同样适用于 3
.所以现在我们知道我们实际上已经写了:
foldMap (+ (Sum 3)) (Just (Sum 5)) :: Sum Int
foldMap
将结构的每个元素映射到一个幺半群(它已经是一个幺半群,但无论如何它会用 3
递增它们),然后执行折叠。所以这意味着我们已经写了这样的东西:(+ (Sum 3)) (Sum 5) <> mempty
对于
Num n => Sum n
输入 mempty
是 Sum 0
,所以这意味着我们写道:(+ (Sum 3)) (Sum 5) <> (Sum 0)
和
(<>)
对于 Sum
是 (+)
,所以这意味着表达式归结为:(+ (Sum 3)) (Sum 5) + (Sum 0)
可以评估为:
(Sum 5 + Sum 3) + Sum 0
或者:
Sum 8
关于haskell - 函数签名如何匹配请求的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51746869/