在Data.Foldable的意义上,哪些是不属于“常规可折叠结构”的可折叠实例?

时间:2018-11-24 17:37:40

标签: haskell foldable

documentation for Foldable列出了“常规可折叠结构”所需的几个属性:

  • 对于foldr

      

    对于一般的可折叠结构,其语义上应与

    相同
    foldr f z = foldr f z . toList
    
  • 对于foldl

      

    对于一般的可折叠结构,其语义上应与

    相同
    foldl f z = foldl f z . toList
    
  • 对于foldl'(对于我来说似乎是错字):

      

    对于一般的可折叠结构,其语义上应与

    相同
    foldl f z = foldl' f z . toList
    

Foldable的哪些实例不需要或不能保留这些属性?

1 个答案:

答案 0 :(得分:3)

据我了解,如果实例定义了这些可选功能,则必须遵循以下规则。默认情况下,Foldable实例仅需要定义foldMapfoldr。从这两个定义之一中,类型类的所有其他功能将自动遵循。

但是,通常,类型类使您可以选择定义更多类型类的行为。如果toList的默认自动定义效率低下,并且您希望提供更有效的实现,则这很有用。对于Monoid类型类,这可能更容易理解,该类将mconcat定义为可选函数“以便可以为特定类型提供优化版本”。

OP中引用的法律是实例,如果您选择自己定义其中一些或全部功能,则必须遵守这些法律。作为违反规则的(荒谬的)类型的示例,请考虑以下Invalid类型:

import Data.Foldable

data Invalid a = Invalid a deriving (Show, Eq)

instance Foldable Invalid where
  foldMap f (Invalid x) = f x
  foldr _ x _ = x -- Unlawful!!
  toList (Invalid x) = [x]

虽然仅需将foldMap定义为Foldable实例,但此实例也定义foldrtoList。尽管toList定义很好,但foldr定义违反了规则:

*Q53460772 Data.Monoid Data.Foldable> toList $ Invalid 42
[42]
*Q53460772 Data.Monoid Data.Foldable> foldMap Sum $ Invalid 42
Sum {getSum = 42}
*Q53460772 Data.Monoid Data.Foldable> f = \x acc -> x + acc
*Q53460772 Data.Monoid Data.Foldable> z = 0
*Q53460772 Data.Monoid Data.Foldable> (foldr f z . toList) $ Invalid 42
42
*Q53460772 Data.Monoid Data.Foldable> foldr f z $ Invalid 42
0

toListfoldMap函数的行为与您期望的一样,但是请注意foldr f z不会产生与foldr f z . toList相同的输出。

尽管Invalid是一个荒谬的示例,但它说明了您可以编写可编译的代码,并且看起来像它提供了Foldable的实例。但是,与每个功能相关的法律和规则清楚地表明这不是有效实例。