[英]Stateful generators with Haskell pipes
Suppose I want to model, using Haskell pipes, a Python Generator[int, None, None]
which keeps some internal state. Should I be using Producer int (State s) ()
or StateT s (Producer int m) ()
, where m
is whatever type of effect I eventually want from the consumer?假设我想要 model,使用 Haskell 管道,Python
Generator[int, None, None]
保留一些内部 state。我应该使用Producer int (State s) ()
还是StateT s (Producer int m) ()
,其中m
是我最终希望从消费者那里得到的任何类型的效果?
How should I think about the notion of transducers in pipes?我应该如何考虑管道中换能器的概念? So in Oleg's simple generators , there is
所以在 Oleg 的简单生成器中,有
type Transducer m1 m2 e1 e2 = Producer m1 e1 -> Producer m2 e2
but I don't know what the analog is in pipes, because any Proxy
objects that interact seem to rely on the same underlying monad m
, not switching from m1
to m2
.但我不知道管道中的模拟是什么,因为任何交互的
Proxy
对象似乎都依赖于相同的底层 monad m
,而不是从m1
切换到m2
。 See the Prelude functions, for instance.例如,请参阅Prelude函数。
I think I'm just misunderstanding something fundamental about the way pipes works.我想我只是误解了管道工作方式的一些基本知识。 Thanks for your help.
谢谢你的帮助。
In pipes
, you typically wouldn't use effects in the base monad m
of your overall Effect
to model the internal state of a Producer
.在
pipes
中,您通常不会在整体Effect
的基本 monad m
中使用 effects 到 model Producer
的内部state。 If you really wanted to use State
for this purpose, it would be an internal implementation detail of the Producer
in question (discharged by a runStateP
or evalStateP
inside the Producer
, as explained below), and the State
would not appear in the Producer
's type.如果您真的想为此目的使用
State
,它将是相关Producer
的内部实现细节(由Producer
内部的runStateP
或evalStateP
,如下所述),并且State
不会出现在Producer
的类型。
It's also important to emphasize that a Producer
, even when it's operating in the Identity
base monad without any "effects" at its disposal, isn't some sort of pure function that would keep producing the same value over and over without monadic help.同样重要的是要强调一个
Producer
,即使它在Identity
base monad 中运行而没有任何“影响”可供其支配,也不是某种纯粹的 function ,它会在没有 monadic 帮助的情况下一遍又一遍地产生相同的值。 A Producer
is basically a stream, and it can maintain state using the usual functional mechanisms (eg, recursion, for one).一个
Producer
基本上是一个 stream,它可以使用通常的功能机制(例如,递归)来维护 state。 So, you definitely don't need a State
for a Producer
to be stateful.因此,您绝对不需要
State
来使Producer
有状态。
The upshot is that the usual model of a Python Generator[int, None, None]
in Pipes
is just a Monad m => Producer Int m ()
polymorphic in an unspecified base monad m
.结果是 Pipes 中 Python
Generator[int, None, None]
的通常Pipes
只是一个Monad m => Producer Int m ()
在未指定的基础 monad m
中多态。 Only if the Producer
needs some external effects (eg, IO
to access the filesystem) would you require more of m
(eg, a MonadIO m
constraint or something).只有当
Producer
需要一些外部效果(例如, IO
来访问文件系统)时,您才会需要更多的m
(例如, MonadIO m
约束或其他东西)。
To give you a concrete example, a Producer
that generates pseudorandom numbers obviously has "state", but a typical implementation would be a "pure" Producer
:给你一个具体的例子,一个生成伪随机数的
Producer
显然有“状态”,但典型的实现是一个“纯” Producer
:
randoms :: (Monad m) => Word32 -> Producer Int m ()
randoms seed = do
let seed' = 1664525 * seed + 1013904223
yield $ fromIntegral seed'
randoms seed'
with the state maintained via recursion.通过递归维护 state。
If you really decided to maintain this state via the State
monad, the type of the Producer
wouldn't change.如果您真的决定通过
State
monad 维护这个 state, Producer
的类型就不会改变。 You'd just use a State
internally.您只需在内部使用
State
。 The Pipes.Lift
module provides some helpers (like evalStateP
used here) to locally add a monad layer to facilitate this: Pipes.Lift
模块提供了一些帮助程序(如此处使用的evalStateP
)来在本地添加一个 monad 层以促进此操作:
randoms' :: (Monad m) => Word32 -> Producer Int m ()
randoms' seed = evalStateP seed $ forever $ do
x <- get
let x' = 1664525 * x + 1013904223
yield $ fromIntegral x'
put x'
Oleg's simple generators are entirely different. Oleg 的简单生成器完全不同。 His producers and consumers produce and consume values only through monadic effects, and "monad changing" is central to the implementation.
他的生产者和消费者仅通过单子效应来生产和消费价值,而“改变单子”是实现的核心。 In particular, I believe his consumers and transducers can only maintain state via a monadic effect, like a
State
monad, though I'd have to look a little more carefully to be sure.特别是,我相信他的消费者和传感器只能通过单子效应来维持 state,就像
State
单子一样,尽管我必须更仔细地观察才能确定。
In contrast, pipes
proxies can produce and consume values and maintain internal state independent of the underlying base monad.相比之下,
pipes
代理可以产生和消费值并维护内部 state 独立于底层基础 monad。
Ultimately, the analog of Oleg's transducers in pipes
are simply the Pipe
s.最终,奥列格在
pipes
中的传感器的模拟只是Pipe
s。 Both consume values from a producer and yield values to a consumer.两者都消耗生产者的价值并向消费者产生价值。 The monad changing in Oleg's transducers is just an implementation detail.
Oleg 的转换器中的 monad 变化只是一个实现细节。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.