为什么Monoid不是foldr / foldl的要求?

时间:2016-06-22 16:42:31

标签: haskell fold monoids foldable

我正在查看Haskell中的Foldable类。其中两个方法foldfoldMap需要一个Monoid实例。但foldrfoldl没有任何此类限制。

fold :: Monoid m => t m -> m
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
foldl :: (b -> a -> b) -> b -> t a -> b

要使foldr / foldl的结果等效,是否应该将给定的折叠函数限制为关联?是否有任何例子表明foldr / foldl的结果在同一个列表中是不同的?

Foldable实例不应该包裹Monoidal值吗?或者可折叠更一般?

1 个答案:

答案 0 :(得分:5)

  

要使foldr / foldl的结果等效,是否应该限制给定的折叠函数是关联的?是否有任何示例foldr / foldl的结果在同一列表中有所不同?

是。如果你传递一个非关联函数(如减法(-)),你将获得不同的结果。正如你正确地指出,没有Monoid实例与(-)之类的东西相对应。

但那是设计上的。对Foldablefoldr必须采用关联函数的foldl个实例没有此类限制。在某些情况下,您可能希望使用减法等方法进行折叠。 Foldable f的实例更关心约束f可以执行的操作。法律特别是:

foldr f z t = appEndo (foldMap (Endo . f) t ) z
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
fold = foldMap id

-- if f is a Functor
foldMap f = fold . fmap f
foldMap f . fmap g = foldMap (f . g)

你可以在消息来源中看到foldr默认使用newtype Endo a = Endo (a -> a)内同态monoid做了一些聪明的事情:

-- | Right-associative fold of a structure.
--
-- @'foldr' f z = 'Prelude.foldr' f z . 'toList'@
foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z

用可能非幺半形的fz构建一个幺半折叠。

最终问题的答案"为什么Monoid不是必需的?"是非常无聊的"因为它更实用,最终没有必要。"

有关详细信息,请参阅启动所有内容的论文Applicative Programming with Effects