关于 Haskell 中的递归方案,我最喜欢的事情之一是广义态射(gcata
等),它允许使用 monad 转换器库来交叉(co-)monadic 计算与递归。例如,如这篇精彩的博客文章中所述。
但是,我遇到了一个问题;为了能够使用这些函数,我们需要 (co-)monads 是 (co-)sequentiable。考虑一个类型签名gana
:
gana : Monad m => (forall z . m (f z) -> f (m z)) -> (a -> f (m a)) -> a -> b
第一个参数本质上说m
必须有一个sequence
运算符。
不幸的是,我发现在实践中,有些单子不是可分配的。例如:
- 表示数据库事务的 monad。中止时,事务可以回滚;如果已排序,则只能回滚到已排序的点。
- 一个并发单子,表示资源上的锁或原子计算。排序后,锁会暂时丢失。
在这种情况下,仍然可以编写一个专门的递归方案来交错单子执行;但是你失去了使用单子变压器融合它的能力。即,如果你想组合这样的非分配单子,它们不能使用变压器与 f-(co) 代数中的单子/共单子进行融合。具体来说,我不能使用 monad 转换器将DBTransaction
monad 与 apomorphism ( ExceptT/EitherT
) 结合起来;我需要从头开始编写自定义递归方案。
我的问题是是否有人有解决此限制的建议。