【发布时间】:2017-01-04 20:53:42
【问题描述】:
我围绕RWS (Reader+Writer+State) monad 的使用构建了一个计算:
newtype Problem a = Problem { unProblem :: RWS MyEnv MyLog MyState a }
deriving ({- lots of typeclasses -})
计算是通过组装形式的基本计算逐步构建的
foo :: a -> Problem b
然而,有时子计算不需要RWS monad 的全部功能。例如,考虑
bar :: c -> State MyState d
我想在Problem monad 的上下文中使用bar 作为更大计算的一部分。我可以看到三种方法来做到这一点,但对我来说,没有一种是很优雅的。
-
手动解包
State计算并将其重新包装在 RWS monad 中:baz :: a -> RWS MyEnv MyLog MyState c baz x = do temp <- foo x initialState <- get let (finalResult, finalState) = runState (bar temp) initialState put finalState return finalResult 修改
bar的类型签名,将其提升到Problemmonad。这样做的缺点是新类型签名没有明确承诺bar独立于MyEnv并且不向MyLog记录任何内容。将
RWSmonad 替换为显式的ReaderT MyEnv WriterT MyLog State MyStatemonad 堆栈。这让我可以简洁地将lift.lift和bar子计算成完整的单子;但是,这个技巧将不起作用,例如对于c -> Reader MyEnv d形式的子计算。
有没有更简洁的方式来编写foo 和bar?我有一种预感,类型类实例的一些巧妙定义可能会解决问题,但我不知道该怎么做。
【问题讨论】:
-
您使用的是变压器包中的 RWS 还是 mtl 中的 RWS?
-
我正在使用
mtl。我其实不知道transformers。
标签: haskell state monads writer reader