[英]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.