假設我想使用 Haskell 管道建模一個
Generator[int, None, None]保持某些內部狀態的 Python。我應該使用Producer int (State s) ()orStateT s (Producer int m) (),我最終想要從消費者那里m得到什么型別的效果?我應該如何看待管道中換能器的概念?所以在 Oleg 的簡單生成器中,有
type Transducer m1 m2 e1 e2 = Producer m1 e1 -> Producer m2 e2但我不知道管道中的模擬是什么,因為任何
Proxy互動的物件似乎都依賴于相同的底層 monadm,而不是從m1to切換m2。例如,參見Prelude函式。
我想我只是誤解了管道作業方式的基本原理。謝謝你的幫助。
uj5u.com熱心網友回復:
在pipes中,您通常不會在m整體的基本單子中使用效果Effect來模擬 a 的內部狀態Producer。如果您真的想State用于此目的,它將是所討論的內部實作細節(由 a或內部Producer釋放,如下所述),并且不會出現在's 型別中。runStatePevalStatePProducerStateProducer
同樣重要的是要強調 a Producer,即使它在Identity基本單子中運行而沒有任何“效果”可供使用,也不是某種純函式,它不會在沒有單子幫助的情況下一遍又一遍地產生相同的值。AProducer基本上是一個流,它可以使用通常的功能機制(例如,遞回)來維護狀態。所以,你絕對不需要aState是Producer有狀態的。
結果是 Python Generator[int, None, None]in的通常模型Pipes只是Monad m => Producer Int m ()未指定的基本 monad 中的多型m。只有當Producer需要一些外部影響(例如,IO訪問檔案系統)時,您才會需要更多m(例如,MonadIO m約束或其他東西)。
舉一個具體的例子,Producer生成偽亂數的 a 顯然具有“狀態”,但典型的實作是“純” Producer:
randoms :: (Monad m) => Word32 -> Producer Int m ()
randoms seed = do
let seed' = 1664525 * seed 1013904223
yield $ fromIntegral seed'
randoms seed'
通過遞回維護狀態。
如果你真的決定通過Statemonad 保持這種狀態,那么 的型別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單子一樣,盡管我必須更仔細地看一下才能確定。
相比之下,pipes代理可以產生和消費值,并獨立于底層基礎 monad 維護內部狀態。
最終,Oleg 的換能器的模擬pipes只是簡單的Pipes。兩者都從生產者那里消費價值,并為消費者提供價值。Oleg 轉換器中的 monad 變化只是一個實作細節。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/454313.html
