简体   繁体   English

管理,定相,组合monad的资源(在Scala或Haskell中)

[英]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堆栈有点困难,因为当你写入getput时,你正在谈论哪一层会让人感到困惑。 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以隔离有状态操作,这些操作仅依赖于整个状态的子集,如incyell并确定它们在类型中的隔离。 We also can still get inner state components using use . 我们还可以使用useget内部状态组件。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM