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