我有函数smallStep :: Command -> Data -> Either StepError Data
,我希望bigStep :: [Command] -> Data -> Either StepError Data
使用它,并使用以下语义:
bigStep [] data = Right data
bigStep c:cs data = do
data' <- bigStep cs data
smallStep c data'
这没有什么令人费解的,但如果smallStep
的类型为Command -> Data -> Data
,我会将bigStep
简称为bigStep commands data = foldr data smallStep commands
。
当然,我也想在这里使用foldr
。我该怎么做呢? foldM
被取消foldl
,倒车清单听起来并不是一个非常好的主意。
答案 0 :(得分:7)
通常,在资源使用方面,左侧折叠不会比右侧折叠更好或更差。但是,我认为[Command]
应该是有序命令的列表,这些命令要按照提供的顺序一个接一个地执行。如果是这种情况,可能最容易向后构建这些列表(而不是反转它们 - 对于长列表来说这确实是一项代价高昂的操作)。如果你不想这样做,这里是一般的monadic右折:
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
请注意以下所有类型:
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
我们可以推断foldrM
确实是一个正确的折叠。
但是,如果你需要fold
一个非常大的列表,上面的两个monadic折叠都是懒惰的,只有在最后一个函数应用程序排序后才会开始评估。