【发布时间】:2013-06-11 23:32:19
【问题描述】:
我有函数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,倒车列表听起来不是一个非常好的主意。
【问题讨论】:
-
最后一行应该是
smallStep c data',不是吗?问题:如果稍后smallStep失败了怎么办?如果这不能发生,则类型错误。如果它可能失败,并且您不想将该失败转变为模式匹配错误,那么据我所知,您的选择是您所拥有的,或者反转和foldM。倒车实际上可能会更好,因为bigStep (c:cs) d = bigStep cs d >>= smallStep c可能会产生更大的冲击。 -
您仍然可以使用
foldr。你只需要给它一个合适的 reducer 函数:(a -> b -> b) = (Data -> E Command -> E Command)(其中E = Either StepError)。你有一个(Data -> Command -> E Command)。那么如何将a -> E b类型的函数扩展 为E a -> E b类型的函数?提示:这是 monad 的基本操作之一。 -
@DanielFischer 我不认为我理解你。如果
smallStep不会失败,那么bigStep将只是一个foldr。但它可以,所以我必须在Eithermonad 周围跳舞。 -
bigStep cs d = foldr ((=<<) . smallStep) (return d) cs