函数签名如何匹配请求的类型
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
。
假设 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
。因此,您编写的 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
我正在尝试了解这是如何工作的;在 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
。
假设 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
。因此,您编写的 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