簡體   English   中英

有 Haskell 個管道的狀態生成器

[英]Stateful generators with Haskell pipes

  1. 假設我想要 model,使用 Haskell 管道,Python Generator[int, None, None]保留一些內部 state。我應該使用Producer int (State s) ()還是StateT s (Producer int m) () ,其中m是我最終希望從消費者那里得到的任何類型的效果?

  2. 我應該如何考慮管道中換能器的概念? 所以在 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內部的runStatePevalStateP ,如下所述),並且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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM