Haskell中RWST结合Maybe的Monad转换器循环短路异常问题
在Haskell的Maybe基RWST中循环执行action直到短路并获取最后一个Just值
我在使用基于Maybe的RWST monad时,需要重复执行action直到它返回Nothing,同时要保留最后一次成功执行(返回Just)的结果。相关类型定义如下:
type St = MyState type Re = MyRead type Wr = MyWriter type Foo = RWST Re Wr St Maybe action :: Foo ()
最初尝试的缺陷
我一开始写了这样的递归实现:
run = action >> run <|> action
但这个写法有问题:如果第二次执行action时触发短路返回Nothing,即便之前有过成功执行的结果,最终也会返回Nothing——因为run的逻辑会重复执行两次action,短路的分支会覆盖之前的成功结果。我查过extra库,没找到合适的现成函数。
解决方案
最简方案:使用many
经过尝试,最简单的解决办法是直接用many函数。many会重复执行action直到它失败,同时收集所有成功执行的结果。如果只需要最后一次成功的结果,取列表的最后一个元素即可:
lastSuccess :: Foo (Maybe ()) lastSuccess = last <$> many action
当many遇到Nothing时会停止执行,返回之前所有成功执行的结果列表,取最后一个就能得到我们需要的最后一次成功结果。
通用场景更优方案:换成MaybeT包装
如果是更通用的业务场景,把RWST的底层monad换成普通的(比如IO),然后用MaybeT来封装短路逻辑会更清晰。调整后的类型定义如下:
type Foo' = MaybeT (RWST Re Wr St IO) action' :: Foo' ()
这种结构下,循环执行直到短路的逻辑更容易控制,也能更直观地处理最后一次成功的结果,避免原RWST+Maybe组合带来的语义歧义。
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

