由FreeT生成的解释器monad变换器的MonadFix实例? [英] MonadFix instance for interpreter monad transformer generated by FreeT?

查看:141
本文介绍了由FreeT生成的解释器monad变换器的MonadFix实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由 FreeT 生成的标准解释器monad变换器的简化版本:

  data InteractiveF pra = Interact p(r  - > a)

type Interactive pr = FreeT(InteractiveF pr)

p 是提示,而 r 是环境......人们可以使用类似的方式运行它:

  runInteractive :: Monad m => (p→m r)→>交互式p r m a  - > m a 
runInteractive提示符iact = do
run< - runFreeT iact
运行
Pure x - >返回x
免费(Interact p f) - > do
response< - 提示符p
runInteractive提示符(f resp)

实例MonadFix m => MonadFix(FreeT(InteractiveF p r))m a)
mfix = - ???

我觉得这个类型或多或少只是一个约束版本 StateT ...如果有的话,一个 Interactive pr IO 是我认为 IO ...我想......但是......好吧,无论如何,我的直觉说应该有一个好例子。



我试着写一个,但是我似乎无法弄清楚。到目前为止,我的最接近的尝试是:
$ b $ $ p $ mfix f = FreeT(mfix(runFreeT。f。breakdown))
其中
分解:: FreeF(InteractiveF pr)a(FreeT(InteractiveF pr)ma) - >
细分(纯x)= x
细分(免费(Interact p r))= - ...?

我也尝试过利用 MonadFix m 的实例,但也没有运气 -

  mfix f = FreeT $ do 
rec ran< - runFreeT(fz)
z< - 运行
Pure x - >返回x
免费iact - > - ...
return - ...

任何人都知道这是不是真的可能,或者为什么不是?如果是这样,我有什么好的地方继续寻找?






另外,在我的实际应用中,我不会甚至不需要使用 FreeT ...我可以使用 Free ;也就是说,让 Interactive 只是一个monad,而不仅仅是一个monad变换器,并且有 $ b

  runInteractive :: Monad m => (p→m r)→>交互式p a  - > ma 
runInteractive _(Pure x)= return x $ b $ runInteractive提示符(Free(Interact pf)= do
response< - 提示符p
runInteractive提示符(f响应)

如果有可能出现这种情况,而不是一般的FreeT情况,我也会很高兴:)

解决方案

试想一下,您已经有了 Interactive 的解释器。

  interpret :: FreeT(InteractiveF pr)ma  - > ma 
interpret = undefined

编写 MonadFix 实例:

 实例MonadFix m => MonadFix(FreeT(InteractiveF p r)m)其中
mfix = lift。 mfix。 (解释)

我们可以直接捕获这个认识中介人的想法,而不需要提供口译员

  { - #LANGUAGE RankNTypes# - } 

数据UnFreeT tma = UnFree { runUnFreeT ::(forall x。tmx - > mx) - > t m a}
- 给出一个从't m'到'm` ^ |的解释器
- 我们在`tm`中有一个类型为^

<$ c的值$ c> UnFreeT 只是一个读取解释器的 ReaderT



code> t 是一个monad转换器, UnFreeT t 也是一个monad转换器。我们可以很容易地从一个计算中构建一个 UnFreeT ,这个计算不需要简单地通过忽略中介就知道解释器。

  unfree :: tma  - > UnFreeT t a 
--unfree = UnFree。 const
unfree x = UnFree $ \_ - > x

实例(MonadTrans t)=> MonadTrans(UnFreeT t)其中
lift = unfree。提升

如果 t 是一个monad transormer, m Monad tm 也是 Monad ,然后 UnFree tm Monad 。给定一个解释器,我们可以将两个需要中介者的计算绑定在一起。

  { - #LANGUAGE FlexibleContexts# - } 

refree ::(forall x。tmx - > mx) - > UnFreeT t m a - > t m a
- refree = flip runUnFreeT
refree解释器x = runUnFreeT x解释器

实例(MonadTrans t,Monad m,Monad(t m))=> Monad(UnFreeT t m)
return = lift。返回
x>>> = k = UnFree $ \interpreter - > runUnFreeT x解释器>> = refree解释器。 k

最后,给定解释器,我们可以修改计算,只要底层monad具有<$ (MonadFix),MonadFix(MonadFix),Monad(tm),MonadFix(MonadFix),MonadFix(MonadFix) )=> MonadFix(UnFreeT t m)其中
mfix f = UnFree $ \interpreter - >电梯 。 mfix $解释器。 refree口译员。 f

一旦我们有了解释器,我们实际上可以做任何潜在的monad可以做的事情。这是因为,一旦我们有一个解释器:: forall x。 t m x - > m x 我们可以做以下所有事情。我们可以从 mx tmx 一直到 UnFreeT tmx 并且再次退出。

  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 - > mx



用法



c $ c> Interactive ,你可以在 UnFreeT 中包装 FreeT p>

  type Interactive pr = UnFreeT(FreeT(InteractiveF pr))

您的解释器仍然会写入以产生 FreeT(InteractiveF pr)ma - > m a 。要将新的交互式prma 一路解释为 ma ,您可以使用

 解释器。 refree解释器

UnFreeT 不再释放尽可能解释者。口译员不能随意决定随时随地做什么。 UnFreeT 中的计算可以请求解释器。当计算要求并使用解释器时,将使用相同的解释器来解释程序中用于开始解释程序的部分。


I have a simplified version of the standard interpreter monad transformer generated by FreeT:

data InteractiveF p r a = Interact p (r -> a)

type Interactive p r = FreeT (InteractiveF p r)

p is the "prompt", and r is the "environment"...one would run this using something like:

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 = -- ???

I feel like this type is more or less just a constrained version of StateT...if anything, an Interactive p r IO is I think a constrained version of IO...I think...but... well, in any case, my intuiton says that there should be a good instance.

I tried writing one but I can't really seem to figure out. My closest attempt so far has been:

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)) = -- ...?

I also tried using a version taking advantage of the MonadFix instance of the m, but also no luck --

mfix f = FreeT $ do
  rec ran <- runFreeT (f z)
      z   <- case ran of
               Pure x -> return x
               Free iact -> -- ...
  return -- ...

Anyone know if this is really possible at all, or why it isn't? If it is, what's a good place for me to keep on looking?


Alternatively, in my actual application, I don't even really need to use FreeT...I can just use Free; that is, have Interactive be just a monad and not just a monad transformer, and have

runInteractive :: Monad m => (p -> m r) -> Interactive p r a -> m a
runInteractive _ (Pure x) = return x
runInteractive prompt (Free (Interact p f) = do
    response <- prompt p
    runInteractive prompt (f response)

If something is possible for this case and not for the general FreeT case, I would also be happy :)

解决方案

Imagine you already had an interpreter for Interactive.

interpret :: FreeT (InteractiveF p r) m a -> m a
interpret = undefined

It would be trivial to write a MonadFix instance:

instance MonadFix m => MonadFix (FreeT (InteractiveF p r) m) where
    mfix = lift . mfix . (interpret .)

We can directly capture this idea of "knowing the interpeter" without committing to an interpreter ahead of time.

{-# 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 is just a ReaderT that reads the interpreter.

If t is a monad transformer, UnFreeT t is also a monad transformer. We can easily build an UnFreeT from a computation that doesn't require knowing the interpreter simply by ignoring the interpeter.

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

If t is a monad transormer, m is a Monad, and t m is also a Monad, then UnFree t m is a Monad. Given an interpreter we can bind together two computations that require the interpeter.

{-# 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

Finally, given the interpreter, we can fix computations as long as the underlying monad has a MonadFix instance.

instance (MonadTrans t, MonadFix m, Monad (t m)) => MonadFix (UnFreeT t m) where
    mfix f = UnFree $ \interpreter -> lift . mfix $ interpreter . refree interpreter . f

We can actually do anything the underlying monad can do, once we have the interpreter. This is because, once we have an interpreter :: forall x. t m x -> m x we can do all of the following. We can go from m x through t m x all the way up to UnFreeT t m x and back down again.

                      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

Usage

For your Interactive, you'd wrap the FreeT in UnFreeT.

type Interactive p r = UnFreeT (FreeT (InteractiveF p r))

Your interpreters would still be written to produce a FreeT (InteractiveF p r) m a -> m a. To interpret the new Interactive p r m a all the way to an m a you'd use

interpreter . refree interpreter

The UnFreeT no longer "frees the interpreter as much as possible". The interpreter can no longer make arbitrary decisions about what to do wherever it wants. The computation in UnFreeT can beg for an interpreter. When the computation begs for and uses an interpreter, the same interpreter will be used to interpret that portion of the program as was used to start interpreting the program.

这篇关于由FreeT生成的解释器monad变换器的MonadFix实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆