我正在尝试编写自己的foldMap函数作为学习Haskell
的例外目前它看起来像这样
class Functor f => Foldable f where
fold :: Monoid m => f m -> m
foldMap :: Monoid m => (a -> m) -> f a -> m
foldMap g a = fold (<>) mempty (fmap g a)
但是在编译时会出现以下错误
Could not deduce (Monoid ((f m -> m) -> fm -> m)) arising from use of 'fold'
from the context (Foldable f) bound by the class declaration for 'Foldable' at (file location)
or from (Monoid m) bound by the type signature for foldMap :: Monoid m => (a -> m) -> f a -> m at (file location
In the expression fold (<>) mempty (fmap g a)
In an equation for 'foldMap':
foldMap g a = fold (<>) mempty (fmap g a)
我无法弄清楚编译器试图告诉我这个错误的内容,有人能告诉我我的foldMap出了什么问题吗?
答案 0 :(得分:10)
也许我们应该用实际的解决方案来回答:
我希望现在很清楚,这是一个可能的定义:
class Functor f => Foldable f where
fold :: Monoid m => f m -> m
foldMap :: Monoid m => (a -> m) -> f a -> m
foldMap g a = fold $ fmap g a
安德鲁和李已经给了你一个高级别的解释,但也许我可以给你另一个观点:
让按照类型来回答这个答案:
我们想要一个函数f a -> m
,其中m
是一个幺半群,f
是一个函子。另外我们有一个函数g :: a -> m
我们可以用来从一些a
进入monoid - 很好。
现在我们得到一些额外的功能:
fold :: f m -> m
fmap :: (a -> b) -> f a -> f b
的f
好的,我们现在需要f a -> m
,如果只有a
是m
,那么我们可以使用fold
... dang。
但是等一下:我们可以使用a
将m
变成g
- 但a
被打包到f
... dang。< / p>
哦等等:我们可以使用f a
将f m
变成fmap
.... ding-ding-ding
所以,让我们这样做:
f a
变为f m
:fmap g a
fold (fmap g a)
或使用$
:
foldMap g a = fold $ fmap g a
让我们尝试一下,我们可以尝试:
module Foldable where
import Data.Monoid
class Functor f => Foldable f where
fold :: Monoid m => f m -> m
foldMap :: Monoid m => (a -> m) -> f a -> m
foldMap g a = fold $ fmap g a
instance Foldable [] where
fold [] = mempty
fold (x:xs) = mappend x (fold xs)
这是一个使用Sum
和[1..4]
:
λ> foldMap Sum [1..4]
Sum {getSum = 10}
对我来说似乎很好。
答案 1 :(得分:0)
Monoid有两个函数mappend
和mempty
,您可以使用(<>)
代替mappend
。
类型规范是可行的,因为编译器根据数据类型为函数插入适当的定义,因此(很高兴)不需要传递相关函数。
您犯的错误是不必要地传递您正在使用的Monoid函数。
例如,如果我定义了一个函数来测试某个列表是否在这样的列表中:
isin :: Eq a => a -> [a] -> Bool
isin equalityFunction a list = any (equalityFunction a) list
我不必要地尝试将equalityFunction
作为参数传递,并且类型签名与它不匹配。
相反,我应该定义
isin :: Eq a => a -> [a] -> Bool
isin a list = any (== a) list
使用Eq
类型类中定义的相等函数的标准名称。
同样,您既不需要也不应该传递(<>)
或empty
个参数。