为什么单子状态不可遍历?

纪尧姆·谢勒(Guillaume Cherel)

直观地,在我看来,可以将遍历与状态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

该定律显然不成立,因为输出动作mappends而输入动作没有。好吧,我们怎么不做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在原来的动作 TrueFalse,结果存储在一张地图,然后有结果状态行动在地图中进行查找。这适用于任何可无限计数的状态域。有关详细信息,请参见此答案

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章