我有FreeT
生成的标准解释器monad转换器的简化版本:
data InteractiveF p r a = Interact p (r -> a)
type Interactive p r = FreeT (InteractiveF p r)
p
是“提示”,而r
是“环境”...可以使用以下内容运行:
runInteractive :: Monad m => (p -> m r) -> Interactive p r m a -> m a
runInteractive prompt iact = do
ran <- runFreeT iact
case ran of
Pure x -> return x
Free (Interact p f) -> do
response <- prompt p
runInteractive prompt (f resp)
instance MonadFix m => MonadFix (FreeT (InteractiveF p r)) m a)
mfix = -- ???
我觉得这种类型或多或少只是StateT
的约束版本...如果有的话,Interactive p r IO
我认为是IO
的约束版本......我想......但是......好吧,无论如何,我的直觉上说应该有一个很好的例子。
我试过写一个,但我似乎无法弄明白。到目前为止,我最接近的尝试是:
mfix f = FreeT (mfix (runFreeT . f . breakdown))
where
breakdown :: FreeF (InteractiveF p r) a (FreeT (InteractiveF p r) m a) -> a
breakdown (Pure x) = x
breakdown (Free (Interact p r)) = -- ...?
我还尝试使用版本利用MonadFix
的{{1}}实例,但也没有运气 -
m
任何人都知道这是否真的可行,或者为什么不是?如果是的话,我继续观看的好地方是什么?
或者,在我的实际应用中,我甚至不需要使用mfix f = FreeT $ do
rec ran <- runFreeT (f z)
z <- case ran of
Pure x -> return x
Free iact -> -- ...
return -- ...
...我可以使用FreeT
;也就是说,Free
只是一个monad而不仅仅是monad变换器,而且
Interactive
如果这种情况有可能而不是一般的FreeT案例,我也会很高兴:)
答案 0 :(得分:5)
想象一下,你已经有Interactive
的翻译。
interpret :: FreeT (InteractiveF p r) m a -> m a
interpret = undefined
编写MonadFix
实例:
instance MonadFix m => MonadFix (FreeT (InteractiveF p r) m) where
mfix = lift . mfix . (interpret .)
我们可以直接捕捉到这个&#34;了解互操作者&#34;没有事先提交翻译。
{-# LANGUAGE RankNTypes #-}
data UnFreeT t m a = UnFree {runUnFreeT :: (forall x. t m x -> m x) -> t m a}
-- given an interpreter from `t m` to `m` ^ |
-- we have a value in `t m` of type a ^
UnFreeT
只是一个ReaderT
来读取解释器。
如果t
是monad变换器,UnFreeT t
也是monad变换器。我们可以轻松地从一个计算中构建一个UnFreeT
,而这个计算并不需要通过忽略插入者来了解解释器。
unfree :: t m a -> UnFreeT t m a
--unfree = UnFree . const
unfree x = UnFree $ \_ -> x
instance (MonadTrans t) => MonadTrans (UnFreeT t) where
lift = unfree . lift
如果t
是monad transormer,m
是Monad
,t m
也是Monad
,则UnFree t m
是Monad
。给定一个解释器,我们可以将两个需要绑定器的计算绑定在一起。
{-# LANGUAGE FlexibleContexts #-}
refree :: (forall x. t m x -> m x) -> UnFreeT t m a -> t m a
-- refree = flip runUnFreeT
refree interpreter x = runUnFreeT x interpreter
instance (MonadTrans t, Monad m, Monad (t m)) => Monad (UnFreeT t m) where
return = lift . return
x >>= k = UnFree $ \interpreter -> runUnFreeT x interpreter >>= refree interpreter . k
最后,给定解释器,只要底层monad具有MonadFix
实例,我们就可以修复计算。
instance (MonadTrans t, MonadFix m, Monad (t m)) => MonadFix (UnFreeT t m) where
mfix f = UnFree $ \interpreter -> lift . mfix $ interpreter . refree interpreter . f
一旦我们有了解释器,我们实际上可以做基础monad可以做的任何事情。这是因为,一旦我们有interpreter :: forall x. t m x -> m x
,我们就可以完成以下所有操作。我们可以从m x
到t m x
一直到UnFreeT t m x
然后再返回。
forall x.
lift :: m x -> t m x
unfree :: t m x -> UnFreeT t m x
refree interpreter :: UnFreeT t m x -> t m x
interpreter :: t m x -> m x
对于Interactive
,您需要将FreeT
打包在UnFreeT
中。
type Interactive p r = UnFreeT (FreeT (InteractiveF p r))
你的口译员仍然会被写成FreeT (InteractiveF p r) m a -> m a
。要将新的Interactive p r m a
一直解释为m a
,请使用
interpreter . refree interpreter
UnFreeT
不再&#34;尽可能地释放解释器&#34;。解释者再也无法决定在任何地方做什么。 UnFreeT
中的计算可以求助翻译。当计算需要并使用解释器时,将使用相同的解释器来解释程序中用于开始解释程序的部分。
答案 1 :(得分:2)
无法编写MonadFix m => MonadFix (Interactive p r)
实例。
您的InteractiveF
是经过深思熟虑的Moore machines的基础算符。摩尔机器提供输出,在您的情况下提示,然后根据输入确定下一个要做的事情,在您的情况下是环境。摩尔机器总是首先输出。
data MooreF a b next = MooreF b (a -> next)
deriving (Functor)
如果我们关注MonadFix
关于为Free
撰写Free (MooreF a b)
个实例,但我们将自己约束于MonadFix
的特定情况,我们最终会确定是否有{{1} Free (MooreF a b)
的实例然后必须存在一个函数
mooreFfix :: (next -> MooreF a b next) -> MooreF a b next
要编写此函数,我们必须构造一个MooreF b (f :: a -> next)
。我们没有任何b
输出。可以想象,如果我们已经拥有下一个b
,我们可以获得a
,但是摩尔机器总是首先输出。
如果您只提前阅读mooreFfix
,则可以在a
附近写一些内容。
almostMooreFfix :: (next -> MooreF a b next) -> a -> MooreF a b next
almostMooreFfix f a = let (MooreF b g) = f (g a)
in (MooreF b g)
f
必须能够独立于参数g
确定next
。要使用的所有可能f
的格式为f next = MooreF (f' next) g'
,其中f'
和g'
是其他一些函数。
almostMooreFFix :: (next -> b) -> (a -> next) -> a -> MooreF a b next
almostMooreFFix f' g' a = let (MooreF b g) = f (g a)
in (MooreF b g)
where
f next = MooreF (f' next) g'
通过一些等式推理,我们可以替换f
右侧的let
almostMooreFFix :: (next -> b) -> (a -> next) -> a -> MooreF a b next
almostMooreFFix f' g' a = let (MooreF b g) = MooreF (f' (g a)) g'
in (MooreF b g)
我们将g
绑定到g'
。
almostMooreFFix :: (next -> b) -> (a -> next) -> a -> MooreF a b next
almostMooreFFix f' g' a = let (MooreF b _) = MooreF (f' (g' a)) g'
in (MooreF b g')
当我们将b
绑定到f' (g' a)
时,let
变得不必要,并且该函数没有递归结。
almostMooreFFix :: (next -> b) -> (a -> next) -> a -> MooreF a b next
almostMooreFFix f' g' a = MooreF (f' (g' a)) g'
非almostMooreFFix
的所有undefined
甚至不需要let
。