foldMap可以通过遍历实现:
foldMap f = getConst . traverse (Const . f)
所以,我的问题是如何通过foldMap实现遍历:
traverse f = ...
OR
it Can't be accomplished ?
答案 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
Foldable
和Blonk
Traversable
唯一可能完全遵纪守法的实施方式。现在有traverse Identity = Identity
的法律:
traverse
让我们看看它是如何发挥作用的,假设foldMap
是根据g
实施的,也就是说,有一些术语h
和f
(如果他们愿意,可以提及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 Blank
或traverse 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
实例进行定义。但是,还有一些类型包含有效的Functor
和Foldable
个实例,不具有有效的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
身份法律不允许我们这次逃脱。