[英]Resources on managing, phasing, composing monads (in Scala or Haskell)
I am looking for resources discussing good practice for composing monads. 我正在寻找资源讨论组成monad的良好实践。 My most pressing problem is that I'm writing a system that is making use of a series of state monads over different state types, and it seems as if the best way to handle this situation is to just create one big product type (perhaps prettied up as a record/class) encompassing all the components I'm interested in even though phase 1 is not interested in component B, and phase 2 is only interested in component A.1.
我最紧迫的问题是我正在编写一个系统,该系统正在使用一系列状态monad而不是不同的状态类型,似乎处理这种情况的最好方法就是创建一个大的产品类型(可能是prettied)即使第1阶段对组件B不感兴趣,第2阶段仅对组件A.1感兴趣,也包括我感兴趣的所有组件。
I'd appreciate pointers to nice discussions of alternatives when writing code in this sort of area. 在这类领域编写代码时,我非常感谢能够很好地讨论替代方案。 My own code-base is in Scala, but I'm happy to read discussions about the same issues in Haskell.
我自己的代码库是在Scala中,但我很高兴阅读有关Haskell中相同问题的讨论。
It's a bit challenging to use stacks of StateT
because it becomes confusing as to which layer you're talking to when you write get
or put
. 使用
StateT
堆栈有点困难,因为当你写入get
或put
时,你正在谈论哪一层会让人感到困惑。 If you use an explicit stack in transformers
style then you have to use a bunch of lift
s and if you use the class-based method of mtl
you get stuck entirely. 如果你在
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)
We might want to avoid that mess with an explicit product type of states. 我们可能希望避免使用明确的产品类型的状态。 Since we end up with functions from our product state to each individual component it's easy to
get
into those individual components using gets
因为我们最终从我们的产品状态,各个组件的功能可以很容易地
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)
But this might be considered ugly still for two reasons: (1) put
and modification in general doesn't have anywhere nearly as nice a story and (2) we can't easily look at the type of a function which only impacts, say, the int
state and know that it doesn't touch str
. 但这可能被认为是丑陋仍有两个原因:(1)
put
和修改一般没有任何地方几乎一样好的故事和(2)我们不能轻易看到只影响的功能的类型,比如说, int
状态并知道它不接触str
。 We'd much prefer to maintain that type-ensured modularity. 我们更喜欢保持这种类型保证的模块化。
If you're lens
-savvy there's a solution called zoom
如果你是
lens
那就是一个名为zoom
的解决方案
-- the real type is MUCH more general
zoom :: Lens' mother child -> StateT child m a -> StateT mother m a
which "lifts" a stateful computation on a subpart of some larger state space up to the entire state space. 它将某个较大状态空间的子部分上的有状态计算“提升”到整个状态空间。 Or, pragmatically, we use it like this:
或者,实际上,我们像这样使用它:
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)
And now most of the problems should have vanished—we can zoom
in to isolate stateful operations which only depend upon a subset of the total state like inc
and yell
and determine their isolation in their type. 现在大多数问题都应该消失了 - 我们可以
zoom
以隔离有状态操作,这些操作仅依赖于整个状态的子集,如inc
和yell
并确定它们在类型中的隔离。 We also can still get
inner state components using use
. 我们还可以使用
use
来get
内部状态组件。
More than this, zoom
can be used to zoom
in on state buried deep inside various tranformer stacks. 除此之外,
zoom
还可用于zoom
深埋在各种变压器堆栈内的状态。 The fully general type works just fine in a situation like this 在这种情况下,完全通用类型可以正常工作
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
But while this is really nice, the fully general zoom
requires some heavy trickery and you can only zoom over some transformer layers. 虽然这非常好,但完全通用的
zoom
需要一些繁重的技巧,你只能放大一些变压器层。 (It's today heavily unclear to me how you add that functionality to your own layer, though presumably it's possible.) (今天我很不清楚你如何将这个功能添加到你自己的图层,尽管可能是这样。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.