如何实现遍历使用foldMap

时间:2018-01-04 10:54:17

标签: haskell typeclass

foldMap可以通过遍历实现:

foldMap f = getConst . traverse (Const . f)

所以,我的问题是如何通过foldMap实现遍历:

traverse f = ...

OR

it Can't be accomplished ?

2 个答案:

答案 0 :(得分:5)

Foldable个实例无法完成。

data Blonk a = Blink | Blank

instance Functor Blonk where
    fmap f Blink = Blink
    fmap f Blank = Blank

instance Foldable Blonk where
    foldMap f _ = mempty

以上是Functor FoldableBlonk Traversable唯一可能完全遵纪守法的实施方式。现在有traverse Identity = Identity 的法律:

traverse

让我们看看它是如何发挥作用的,假设foldMap是根据g实施的,也就是说,有一些术语hf(如果他们愿意,可以提及traverse f = g . foldMap h

traverse f x = g (foldMap h x)
             = g mempty
-- THEREFORE
traverse Identity x = g mempty

然后:

g mempty

请注意,x不依赖于Identity Blink,因此必须为Identity Blanktraverse Identity Blank = Identity Blink != Identity Blank 才能适合该类型。在前一种情况下,

traverse Identity Blink

违反了法律。同样地,Traversable证明在另一案件中违反了法律。

(而且,为了证明我没有扯下任何拳头,有一个守法instance Traversable Blonk where traverse f Blink = pure Blink traverse f Blank = pure Blank 实例:

mapGetters

答案 1 :(得分:0)

Daniel Wagner给出了一个非常好的示例,其中包含一个有效Traversable实例的类型,该实例无法根据其Foldable实例进行定义。但是,还有一些类型包含有效的FunctorFoldable个实例,具有有效的Traversable个实例。主要原因是Foldable实际上没有法律规定。

例如,如果我们想要,我们可以写

instance Foldable IO where
  foldMap _ _ = mempty

这样的实例比实用更容易混淆,但是它本身并没有错误的。但是当我们尝试编写Traversable IO的实例时会发生什么?

traverse f m = _1
-- m :: IO a
-- f :: a -> f b
-- _1 :: f (IO b)

好的,所以我们需要制作f (IO b)类型的东西。我们尚未在f中包含任何内容,因此我们无法使用<*>来制作它;我们只能使用pure

traverse f m = pure _2
-- m :: IO a
-- f :: a -> f b
-- _2 :: IO b
哦,哦。我们知道如何设置f b值,但我们无法生成b值。有时IO允许我们使用例外,但Traversable身份法律不允许我们这次逃脱。