您的类型看起来有点像Apfelmus 的operational
monad Freer
,也称为monad:
data Program inst a where
Return :: a -> Program inst a
Bind :: inst a -> (a -> Program inst b) -> Program inst b
instance Monad (Program inst) where
return = Return
Return x >>= f = f x
Bind i next >>= f = Bind i (fmap (>>= f) next)
-- plus the usual Functor and Applicative boilerplate
Program :: (* -> *) -> * -> *
表示指令 inst
序列,它们使用它们的类型参数来指示在解释器中运行该指令的“返回类型”。构造Bind
函数接受一个指令和一个可以在从解释器接收到指令结果后运行的延续。注意如何a
存在量化,反映了计算中所有中间步骤的类型与整体类型无关的事实。
与您的类型之间的重要区别在于Program
响应的类型由指令确定,而不是在整个计算中固定。这使我们能够对每个请求期望引起的响应做出更细粒度的保证。
例如,这里的状态单子写成Program
:
data StateI s r where
Get :: StateI s s
Put :: s -> StateI s ()
type State s = Program (StateI s)
get :: State s s
get = Bind Get Return
put :: s -> State s ()
put s = Bind (Put s) Return
modify :: (s -> s) -> State s ()
modify f = do
x <- get
put (f x)
runState :: State s a -> s -> (s, a)
runState (Return x) s = (s, x)
runState (Bind Get next) s = runState (next s) s
runState (Bind (Put s) next) _ = runState (next ()) s
共同米田引理告诉我们 与Program
同构Free
。直观地说,它是一个基于->
'Functor
实例的免费 monad。对于某些操作,如左关联绑定,Program
可能比 更有效Free
,因为它>>=
基于函数组合,而不是可能昂贵地fmap
ping 任意Functor
.