[英]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. 似乎
FreeT
和Coroutine
是同构的。 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: 我有以下问题:
FreeT
and Coroutine
types? FreeT
和Coroutine
类型之间有什么关系? Why didn't the author of "Coroutine Pipelines" use the FreeT
type instead of creating the Coroutine
type? FreeT
类型而不是创建Coroutine
类型? 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? 我想可以编写基于
FreeT
的Proxy
或Pipe
数据类型,所以我想知道它为什么没有完成? 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.