[英]Resources on managing, phasing, composing monads (in Scala or Haskell)
我正在尋找資源討論組成monad的良好實踐。 我最緊迫的問題是我正在編寫一個系統,該系統正在使用一系列狀態monad而不是不同的狀態類型,似乎處理這種情況的最好方法就是創建一個大的產品類型(可能是prettied)即使第1階段對組件B不感興趣,第2階段僅對組件A.1感興趣,也包括我感興趣的所有組件。
在這類領域編寫代碼時,我非常感謝能夠很好地討論替代方案。 我自己的代碼庫是在Scala中,但我很高興閱讀有關Haskell中相同問題的討論。
使用StateT
堆棧有點困難,因為當你寫入get
或put
時,你正在談論哪一層會讓人感到困惑。 如果你在transformers
風格中使用顯式堆棧,那么你必須使用一堆lift
,如果你使用mtl
的基於類的方法,你會完全陷入困境。
-- using transformers explicit stack style
type Z a = StateT Int (StateT String IO) a
go :: Z ()
go = do int <- get
str <- lift get
replicateM int (liftIO $ putStrLn str)
我們可能希望避免使用明確的產品類型的狀態。 因為我們最終從我們的產品狀態,各個組件的功能可以很容易地get
到使用這些單個組件gets
data ZState = ZState { int :: Int, str :: String }
type Z a = StateT ZState IO a
go :: Z ()
go = do i <- gets int
s <- gets str
replicateM i (liftIO $ putStrLn s)
但這可能被認為是丑陋仍有兩個原因:(1) put
和修改一般沒有任何地方幾乎一樣好的故事和(2)我們不能輕易看到只影響的功能的類型,比如說, int
狀態並知道它不接觸str
。 我們更喜歡保持這種類型保證的模塊化。
如果你是lens
那就是一個名為zoom
的解決方案
-- the real type is MUCH more general
zoom :: Lens' mother child -> StateT child m a -> StateT mother m a
它將某個較大狀態空間的子部分上的有狀態計算“提升”到整個狀態空間。 或者,實際上,我們像這樣使用它:
data ZState = ZState { _int :: Int, _str :: String }
makeLenses ''ZState
type Z = StateT ZState IO a
inc :: MonadState Int m => m ()
inc = modify (+1)
yell :: MonadState String m => m ()
yell = modify (map toUpper)
go :: Z ()
go = do zoom int $ do inc
inc
inc
zoom str yell
i <- use int
s <- use str
replicateM i (liftIO $ putStrLn s)
現在大多數問題都應該消失了 - 我們可以zoom
以隔離有狀態操作,這些操作僅依賴於整個狀態的子集,如inc
和yell
並確定它們在類型中的隔離。 我們還可以使用use
來get
內部狀態組件。
除此之外, zoom
還可用於zoom
深埋在各種變壓器堆棧內的狀態。 在這種情況下,完全通用類型可以正常工作
type Z a = EitherT String (ListT (StateT ZState IO)) a
>>> :t zoom int :: EitherT String (ListT (StateT Int IO)) a -> Z a
zoom int :: EitherT String (ListT (StateT Int IO)) a -> Z a
雖然這非常好,但完全通用的zoom
需要一些繁重的技巧,你只能放大一些變壓器層。 (今天我很不清楚你如何將這個功能添加到你自己的圖層,盡管可能是這樣。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.