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

Mic*_*ish 4 monads haskell scala

我正在寻找资源讨论组成monad的良好实践.我最紧迫的问题是我正在编写一个系统,该系统正在使用一系列状态monad而不是不同的状态类型,似乎处理这种情况的最好方法就是创建一个大的产品类型(可能是prettied)即使第1阶段对组件B不感兴趣,第2阶段仅对组件A.1感兴趣,也包括我感兴趣的所有组件.

在这类领域编写代码时,我非常感谢能够很好地讨论替代方案.我自己的代码库是在Scala中,但我很高兴阅读有关Haskell中相同问题的讨论.

J. *_*son 8

使用堆栈有点困难,StateT因为当你写get或者你正在谈论哪一层时会变得令人困惑put.如果你在transformers样式中使用显式堆栈,那么你必须使用一堆lifts,如果你使用基于类的方法,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)
Run Code Online (Sandbox Code Playgroud)

我们可能希望避免使用明确的产品类型的状态.由于我们最终得到了从产品状态到每个单独组件的功能,因此很容易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)
Run Code Online (Sandbox Code Playgroud)

但这可能被认为是丑陋仍然有两个原因:(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 
Run Code Online (Sandbox Code Playgroud)

它将某个较大状态空间的子部分上的有状态计算"提升"到整个状态空间.或者,实际上,我们像这样使用它:

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)
Run Code Online (Sandbox Code Playgroud)

现在大多数的问题应该已经消失,我们可以zoom在隔离状态操作只取决于国家总像一个子集inc,并yell和确定其类型的隔离.我们还可以get使用内部状态组件use.

不仅如此,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
Run Code Online (Sandbox Code Playgroud)

虽然这非常好,但完全通用zoom需要一些重要的技巧,你只能缩放一些变压器层.(今天我很不清楚你如何将这个功能添加到你自己的图层,尽管可能是这样.)