将计算从State monad提升到RWS monad

阿雷克·富

我围绕RWSReader+ Writer+ State)monad的使用来构建计算

newtype Problem a = Problem { unProblem :: RWS MyEnv MyLog MyState a }
                    deriving ({- lots of typeclasses -})

通过组装形式的基本计算逐步建立计算

foo :: a -> Problem b

但是,有时子计算不需要RWS单子的全部功能例如,考虑

bar :: c -> State MyState d

我想barProblemmonad的上下文中用作较大计算的一部分我可以看到执行此操作的三种方法,但对我而言,这三种方法都不是很优雅。

  1. 手动解包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
    
  2. bar通过将它的类型签名提升到Problemmonad中来进行修改。不利之处在于,新类型签名没有明确承诺bar独立于且不MyEnv记录任何内容MyLog

  3. RWS显式ReaderT MyEnv WriterT MyLog State MyStatemonad堆栈替换monad。这使我可以lift.lift将子计算bar简化为完整的monad。但是,此技巧不适用于例如形式为的子计算c -> Reader MyEnv d

是否有一个更清洁的方式来撰写foobar我有种预感,一些聪明的类型类实例定义可能会解决这个问题,但是我无法确切知道如何进行。

亚历克

我假设您正在使用mtl(如果不使用,请考虑这样做-这些库几乎兼容,除了以下内容)。你可以得到的情况下MonadReader MyEnvMonadWriter MyLogMonadState MyState然后,您可以使用它们在具有此类约束的任何monad堆栈上泛化函数

{-# LANGUAGE GeneralizedNewtypeDeriving, MultiParamTypeClasses, FlexibleContexts #-}

import Control.Monad.RWS
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State

newtype Problem a = Problem { unProblem :: RWS MyEnv MyLog MyState a }
                    deriving (Functor, Applicative, Monad,
                              MonadReader MyEnv, MonadWriter MyLog, MonadState MyState)

从您的示例中,也许bar只需要知道存在某种状态MyState,就可以给它签名

bar :: MonadState MyState m => c -> m d
bar = ...

然后,即使对于foo可能需要全部RWS功能的,您也可以编写

foo :: (MonadState MyState m, MonadReader MyEnv m, MonadWriter MyLog m) => a -> m b
foo = ...

然后,您可以根据自己的喜好混合并匹配它们:

baz :: Problem ()
baz = foo 2 >> bar "hi" >> return ()

现在,为什么这通常有用?它归结为单子“堆栈”的灵活性。如果明天您决定实际上并不需要,RWS而只需State,则可以进行相应的重构Problem,并且bar(首先是仅需要的状态)将继续工作,而无需进行任何更改。

一般情况下,我尽量避免使用WriterTStateTRWST像等内部辅助功能foobar选择在那里让你的代码的通用和使用类型类实现独立的地MonadWriterMonadStateMonadReader,等。然后,你只需要使用WriterTStateTRWST一旦你的代码中:当你真正“跑”的单子。

关于的旁注 transformers

如果您使用transformers,那么这些都无效。这不一定是一件坏事:mtl由于始终能够“查找”组件(例如state或writer)存在一些问题

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何将fclabels镜头提升到Monad?

来自分类Dev

Scala和State Monad

来自分类Dev

Haskell State Monad的解释

来自分类Dev

如何使用 State Monad

来自分类Dev

什么是RWS Monad,何时使用

来自分类常见问题

在Scala中编写State Monad

来自分类Dev

State Monad-While循环

来自分类Dev

隐藏State monad的type参数

来自分类Dev

使用State Monad插入树

来自分类Dev

在Scala中编写State Monad

来自分类Dev

定义嵌套Monad的Monad

来自分类Dev

Haskell State monad,元组为state

来自分类Dev

无状态State monad的状态转换

来自分类Dev

How to put mutable Vector into State Monad

来自分类Dev

在使用State Monad时理解符号“ <-”吗?

来自分类Dev

访问State Monad Haskell中的计数

来自分类Dev

Haskell State Monad函数和参数

来自分类Dev

使用Monad.Writer计算正弦函数

来自分类Dev

我需要计算State Monad中该州剩余元素的次数

来自分类Dev

如何用State monad计算Haskell中列表中的偶数个整数?

来自分类Dev

Haskell:如何严格控制RWS monad的副作用

来自分类Dev

试图使绑定工作于State和Delayed Monad的组合

来自分类Dev

使用State Monad在2D迷宫中查找单词

来自分类Dev

在Haskell中使用State monad进行广度优先搜索

来自分类Dev

Haskell State Monad和Binary不输出所有内容

来自分类Dev

Find word in 2d maze using State monad

来自分类Dev

为什么通常用newtype代替state monad的type

来自分类Dev

在State monad上实现递归关系(在Haskell或Scala中)

来自分类Dev

Trying to get bind working for combination of State and Delayed monad