直观地,在我看来,可以将遍历与状态monad一起使用,例如:
traverse (\a -> [a, a+1]) (state (\s -> (1, s + 1)))
= [state (\s -> (1, s + 1), state (\s -> (2, s + 1)]
但是状态monad没有实现Traversable类型类。这是为什么?我试图找出一种为状态monad实现遍历的方法,看来困难在于提取状态monad的结果以便将其传递给作为遍历的第一个参数给出的函数。不可能吗
要实现Traversable t
,您需要实现以下类型的功能:
sequenceA :: forall f a. Applicative f => t (f a) -> f (t a)
当t
为时State s
,它将变为:
sequenceA :: forall f a. Applicative f => State s (f a) -> f (State s a)
显然,我们不能为所有代码s
编写实现,因为我们必须知道如何创建s
一个f a
空或一个空才能继续。那将是一个矛盾。
但是有可能编写一个满足某些特定类s
的类型的实例。如果我们假设s
是a Monoid
,我们可以这样做:
instance (Monoid m) => Traversable (State m) where
sequenceA (State run) = fmap (\a -> State (\s' -> (mappend s s', a)) fa
where (s, fa) = run mempty
但这不符合Traversable
法律。法律之一是:
traverse Identity = Identity
(回想一下traverse f = sequence . fmap f
)
该定律显然不成立,因为输出动作mappend
s而输入动作没有。好吧,我们怎么不做mappend
:
instance (Monoid m) => Traversable (State m) where
sequenceA (State run) = fmap (\a -> State (\_ -> (s, a)) fa
where (s, fa) = run mempty
这没有帮助,因为现在输出动作会忽略其输入并替换,mempty
而输入动作则不会。
这并不意味着不存在s
无法构造合法Traverse (State s)
实例的类型。例如,State ()
减小到Identity
,这绝对是可遍历的。
如果我们能做State ()
,为什么不State Bool
呢?我们只需runState
在原来的动作都 True
和False
,结果存储在一张地图,然后有结果状态行动在地图中进行查找。这适用于任何可无限计数的状态域。有关详细信息,请参见此答案。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句