简体   繁体   English

Haskell的FreeT和Coroutine类型之间有什么关系

[英]what is the relationship between Haskell's FreeT and Coroutine type

In the "Coroutine Pipelines" article in Monad.Reader Issue 19 , the author defines a generic Coroutine type: Monad.Reader Issue 19中的“Coroutine Pipelines”文章中,作者定义了一个通用的Coroutine类型:

newtype Coroutine f m a = Coroutine
  { resume :: m (Either (f (Coroutine f m a)) a)
  }

I noticed that this type is very similar to the FreeT type from the free package: 我注意到这种类型与free软件包中的FreeT类型非常相似:

data FreeF f a b = Pure a | Free (f b)

newtype FreeT f m a = FreeT
  { runFreeT :: m (FreeF f a (FreeT f m a))
  }

It seems that FreeT and Coroutine are isomorphic. 似乎FreeTCoroutine是同构的。 Here are the functions mapping from one to the other: 以下是从一个映射到另一个的函数:

freeTToCoroutine
  :: forall f m a. (Functor f, Functor m) => FreeT f m a -> Coroutine f m a
freeTToCoroutine (FreeT action) = Coroutine $ fmap f action
  where
    f :: FreeF f a (FreeT f m a) -> Either (f (Coroutine f m a)) a
    f (Pure a) = Right a
    f (Free inner) = Left $ fmap freeTToCoroutine inner

coroutineToFreeT
  :: forall f m a. (Functor f, Functor m) => Coroutine f m a -> FreeT f m a
coroutineToFreeT (Coroutine action) = FreeT $ fmap f action
  where
    f :: Either (f (Coroutine f m a)) a -> FreeF f a (FreeT f m a)
    f (Right a) = Pure a
    f (Left inner) = Free $ fmap coroutineToFreeT inner

I have the following questions: 我有以下问题:

  1. What is the relationship between the FreeT and Coroutine types? FreeTCoroutine类型之间有什么关系? Why didn't the author of "Coroutine Pipelines" use the FreeT type instead of creating the Coroutine type? 为什么“Coroutine Pipelines”的作者不使用FreeT类型而不是创建Coroutine类型?
  2. Is there some sort of deeper relationship between free monads and coroutines? 免费monad和协同程序之间是否存在某种更深层次的关系? It doesn't seem like a coincidence that the types are isomorphic. 类型是同构的似乎并不是巧合。
  3. Why aren't popular streaming libraries in Haskell based around FreeT ? 为什么Haskell中流行的流媒体库不是基于FreeT

    The core datatype in pipes is Proxy : pipes的核心数据类型是Proxy

     data Proxy a' ab' bmr = Request a' (a -> Proxy a' ab' bmr ) | Respond b (b' -> Proxy a' ab' bmr ) | M (m (Proxy a' ab' bmr)) | Pure r 

    The core datatype in conduit is Pipe : conduit的核心数据类型是Pipe

     data Pipe lioumr = HaveOutput (Pipe lioumr) (m ()) o | NeedInput (i -> Pipe lioumr) (u -> Pipe lioumr) | Done r | PipeM (m (Pipe lioumr)) | Leftover (Pipe lioumr) l 

    I imagine it would be possible to write the Proxy or Pipe datatypes based around FreeT , so I wonder why it is not done? 我想可以编写基于FreeTProxyPipe数据类型,所以我想知道它为什么没有完成? Is it for performance reasons? 是出于性能原因吗?

    The only hint of FreeT I've seen in the popular streaming libraries is pipes-group , which uses FreeT to group items in streams. 我在流行的流媒体库中看到的FreeT的唯一提示是pipes-group ,它使用FreeT中的项目进行分组。

To answer your second question, let's first simplify the problem by looking at Free . 要回答你的第二个问题,让我们首先通过查看Free简化问题。 Free fa allows you to construct f -shaped ASTs of a -values for later reduction (aka, interpretation). Free fa允许你构造a f形AST,以便以后减少(也就是说,解释)。 When comparing the monad transformers in the article with unlifted free constructions, we can simply choose Identity for m , as is the usual practice for constructing base monads from their transformers: Free f = FreeT Identity f . 当比较文章中的monad变换器与未提升的自由构造时,我们可以简单地选择Identity for m ,这是从变换器构造基monad的通常做法: Free f = FreeT Identity f

The Monad Reader article first presents a lifted Trampoline monad transformer, so let's start by looking at the unlifted version, with Identity elided: Monad Reader的文章首先介绍了一个提升的Trampoline Monad变换器,所以让我们首先看一下未提升的版本,其中Identity被删除:

data Trampoline a = Return a | Bounce (Trampoline a)

If we compare this to Free 如果我们将此与Free进行比较

data Free f r = Pure r | Free (f (Free f r))

and squint a bit, we can see that all we really need to do is "remove" the f -structure, just as we previously "removed" the m -structure. 稍微斜视一下,我们可以看到我们真正需要做的就是“移除” f结构,就像我们之前“移除” m结构一样。 So, we have Trampoline = Free Identity , again because Identity has no structure. 所以,我们有Trampoline = Free Identity ,因为Identity没有结构。 That, in turn, means that this trampoline is a FreeT Identity Identity : a sort of degenerate coroutine with trivial shape and no way to use effects to determine whether to bounce or return. 反过来,这意味着这个蹦床是一个FreeT Identity Identity :一种简单的FreeT Identity Identity协程,无法使用效果确定是否反弹或返回。 So that's the difference between this trampoline and the trampoline monad transformer: the transformer allows the bounces to be interleaved with m -actions. 这就是这个蹦床和蹦床monad变压器之间的区别:变压器允许弹跳与m -actions交错。

With a bit of work, we can also see that generators and consumers are free monads for specific choices of f , respectively ((,) a) and ((->) a) . 通过一些工作,我们还可以看到生成器和消费者是f特定选择的免费monad,分别是((,) a)((->) a) Their free monad transformer versions similarly allow them to interleave m -actions (eg, a generator can ask for user input before yielding). 他们的免费monad变换器版本同样允许它们交错m -actions(例如,发生器可以在屈服之前请求用户输入)。 Coroutine generalizes both f , the AST shape (fixed to f ~ Identity for Trampoline) and the type of effects which can be interleaved (fixed to no effects, or m ~ Identity ) for Free . Coroutine概括两者f中,AST形状(固定为f ~ Identity用于蹦床)和其可交错效果的类型(固定为无影响,或m ~ Identity )为Free This is exactly FreeT mf . 这正是FreeT mf

Intuitively, if Free f is the monad for pure construction of f -shaped ASTs then FreeT mf is the monad for constructing f -shaped ASTs interleaved with effects supplied by m . 直觉上,如果Free f是用于构造f形AST的monad那么FreeT mf是用于构造与m提供的效果交错的f形AST的monad。 If you squint a bit, this is exactly what coroutines are: a full generalization that parameterizes a reified computation on both the shape of the constructed AST and the type of effects used to construct it. 如果你稍微眯一下,这正是协同程序的完整概括:在构造的AST的形状和用于构造它的效果类型上参数化计算的计算。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM