[英]Stateful generators with Haskell pipes
假設我想要 model,使用 Haskell 管道,Python Generator[int, None, None]
保留一些內部 state。我應該使用Producer int (State s) ()
還是StateT s (Producer int m) ()
,其中m
是我最終希望從消費者那里得到的任何類型的效果?
我應該如何考慮管道中換能器的概念? 所以在 Oleg 的簡單生成器中,有
type Transducer m1 m2 e1 e2 = Producer m1 e1 -> Producer m2 e2
但我不知道管道中的模擬是什么,因為任何交互的Proxy
對象似乎都依賴於相同的底層 monad m
,而不是從m1
切換到m2
。 例如,請參閱Prelude函數。
我想我只是誤解了管道工作方式的一些基本知識。 謝謝你的幫助。
在pipes
中,您通常不會在整體Effect
的基本 monad m
中使用 effects 到 model Producer
的內部state。 如果您真的想為此目的使用State
,它將是相關Producer
的內部實現細節(由Producer
內部的runStateP
或evalStateP
,如下所述),並且State
不會出現在Producer
的類型。
同樣重要的是要強調一個Producer
,即使它在Identity
base monad 中運行而沒有任何“影響”可供其支配,也不是某種純粹的 function ,它會在沒有 monadic 幫助的情況下一遍又一遍地產生相同的值。 一個Producer
基本上是一個 stream,它可以使用通常的功能機制(例如,遞歸)來維護 state。 因此,您絕對不需要State
來使Producer
有狀態。
結果是 Pipes 中 Python Generator[int, None, None]
的通常Pipes
只是一個Monad m => Producer Int m ()
在未指定的基礎 monad m
中多態。 只有當Producer
需要一些外部效果(例如, IO
來訪問文件系統)時,您才會需要更多的m
(例如, MonadIO m
約束或其他東西)。
給你一個具體的例子,一個生成偽隨機數的Producer
顯然有“狀態”,但典型的實現是一個“純” Producer
:
randoms :: (Monad m) => Word32 -> Producer Int m ()
randoms seed = do
let seed' = 1664525 * seed + 1013904223
yield $ fromIntegral seed'
randoms seed'
通過遞歸維護 state。
如果您真的決定通過State
monad 維護這個 state, Producer
的類型就不會改變。 您只需在內部使用State
。 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 的簡單生成器完全不同。 他的生產者和消費者僅通過單子效應來生產和消費價值,而“改變單子”是實現的核心。 特別是,我相信他的消費者和傳感器只能通過單子效應來維持 state,就像State
單子一樣,盡管我必須更仔細地觀察才能確定。
相比之下, pipes
代理可以產生和消費值並維護內部 state 獨立於底層基礎 monad。
最終,奧列格在pipes
中的傳感器的模擬只是Pipe
s。 兩者都消耗生產者的價值並向消費者產生價值。 Oleg 的轉換器中的 monad 變化只是一個實現細節。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.