Haskell 将foldr提升到monad

Haskell 将foldr提升到monad,haskell,monads,fold,Haskell,Monads,Fold,我有函数smallStep::Command->Data->any step error Data,我想用它来制作bigStep::[Command]->Data->any step error Data,语义如下: bigStep [] data = Right data bigStep c:cs data = do data' <- bigStep cs data smallStep c data' bigSte

我有函数
smallStep::Command->Data->any step error Data
,我想用它来制作
bigStep::[Command]->Data->any step error Data
,语义如下:

bigStep []   data   = Right data
bigStep c:cs data   = do
               data' <- bigStep cs data
               smallStep c data'
bigStep[]数据=正确的数据
bigStep c:cs data=do
data'data->data
,我将实现
bigStep
作为
bigStep命令data=foldr data smallStep命令


当然,我也想在这里使用
foldr
。我该怎么做
foldM
被取消了
foldl
,而反向列表听起来并不是一个非常好的主意。

一般来说,就资源使用而言,左折叠不会比右折叠好或坏。但是,我假设
[Command]
应该是一个序列命令列表,这些命令将按照提供的顺序依次执行。如果是这样的话,从一开始就向后构建这些列表可能是最容易的(而不是反转它们——对于长列表来说,这确实是一个代价高昂的操作)。如果您不想这样做,这里有一个通用的单子右折叠:

foldrM :: Monad m => (a -> b -> m b) -> b -> [a] -> m b
foldrM f d []     = return d
foldrM f d (x:xs) = (\z -> f x z) =<< foldrM f d xs
我们可以推断,
foldrM
确实是一个右折叠


但是,如果需要折叠一个非常大的列表,上面的两个一元折叠都是惰性的,只有在最后一个函数应用程序排序后才会开始计算

最后一行应该是
smallStep c data'
,不是吗?问题:如果稍后的
smallStep
失败怎么办?如果不能做到这一点,那么类型是错误的。如果它可能失败,并且您不想将该失败转化为模式匹配错误,那么在我看来,您的选项就是您所拥有的,或者反转和
foldM
。实际上,反转可能更好,因为
bigStep(c:cs)d=bigStep cs d>=smallStep c
可能会产生更大的震动。您仍然可以使用
foldr
。你只需要给它一个合适的减速机函数:
(a->b->b)=(Data->E Command->E Command)
(其中
E=任一步错误
)。您有一个
(数据->命令->E命令)
。那么,如何将
a->eb
类型的函数扩展为
ea->eb
类型的函数呢?提示:这是单子的基本操作之一。@DanielFischer我想我不明白你的意思。如果
smallStep
不能失败,
bigStep
将只是一个
foldr
。但是它可以,所以我必须绕着
或者
单子跳舞。
bigStep cs d=foldr((=
foldl :: (a -> b -> a) -> a -> [b] -> a
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

foldr :: (a -> b -> b) -> b -> [a] -> b
foldrM :: Monad m => (a -> b -> m b) -> b -> [a] -> m b