FreeT / ProgramT 创建的 monad 转换器是否有类似 mtl 的机制?
我对历史的理解如下。曾几何时,monad 转换器被发明了。然后人们开始一个接一个地堆叠 monad 转换器,然后发现lift
到处都插入很烦人。然后有几个人发明了单子类,这样我们就可以ask :: m r
在任何单子m
中这样MonadReader r m
。这可以通过让每个 monad 类渗透到每个 monad 转换器来实现,例如
(Monoid w, MonadState s m) => MonadState s (WriterT w m)
MonadWriter w m => MonadWriter w (StateT s m)
对于每对 monad 转换器,您都需要这样一对实例声明,因此当有n 个monad 转换器时,有n ^2 成本。然而,这并不是一个大问题,因为人们大多会使用预定义的 monad,而很少创建自己的。到目前为止我了解的故事,并且在以下问答中也有详细说明:
然后我的问题是新的 Free monads http://hackage.haskell.org/package/free和 Operational monads http://hackage.haskell.org/package/operational。它们允许我们编写自己的 DSL 并将其用作 monad,只需将语言定义为某种代数data
类型(操作甚至不需要Functor
实例)。好消息是我们可以免费获得 monad 和 monad 转换器;那么monad类呢?坏消息是“我们很少定义自己的 monad 转换器”的假设不再成立。
作为理解这个问题的尝试,我做了两个ProgramT
s,让它们互相穿透;
https://github.com/nushio3/practice/blob/master/operational/exe-src/test-05.hs
该operational
包不支持 monad 类,因此我采用了另一个实现minioperational
并对其进行了修改以根据需要进行工作;https://github.com/nushio3/minioperational
不过,我需要专门的实例声明
instance (Monad m, Operational ILang m) => Operational ILang (ProgramT SLang m) where
因为以下形式的一般声明会导致无法确定的情况。
instance (Monad m, Operational f m) => Operational f (ProgramT g m) where
我的问题是,我们怎样才能更容易让我们的操作单子相互渗透。或者,我是否希望对任何不合时宜的 Operational monad 有所了解。
我也想知道正确的渗透技术术语:)