这个Monad Stack功能的名称是什么?

时间:2011-05-11 17:10:05

标签: haskell monads monad-transformers state-monad

我在状态monad中有一堆有状态函数。程序中的某一点需要有一些IO操作,所以我将IO包装在StateT中,获得了这样的一对类型:

mostfunctions :: State Sometype a
toplevel :: StateT Sometype IO a

为了简单起见,我不想将IO上下文传递给主要的函数集,我想避免将它们包装在monad堆栈类型中。但是为了从顶层功能中调用它们,我需要一些类似于升力的东西,但我并不是想从内部单子中取出一个值。相反,我想将StateT monad中的状态转换为State monad中的等价物。要做到这一点,我有以下几点:

wrapST :: (State Sometype a) -> StateT Sometype IO a
wrapST f = do s <- get
              let (r,s2) = runState f s 
              put s2
              return r

然后习惯于交错,如下所示:

toplevel = do liftIO $ Some IO functions
              wrapST $ Some state mutations
              liftIO $ More IO functions
              ....

这似乎是一个相当明显的代码块,所以我想知道这个函数是否有标准名称,它已经在标准库中的某个地方实现了?我试图保持描述简单,但显然这延伸到将一个变换器拉出堆栈,将包装的值转换为变换器类型的表兄弟,跳过堆栈中的下面的monad,然后将结果推回到结束。

2 个答案:

答案 0 :(得分:9)

重构代码以使用类型StateT SomeType m a而不是State SomeType a可能是个好主意,因为第一个代码与任意monad堆栈兼容。如果您像这样更改它,则不再需要函数wrapST,因为您可以直接调用有状态函数。

好。假设您有一个函数subOne :: Monad m => State Int Int

subOne = do a <- get
            put $ a - 1
            return a

现在,将此类函数的类型从State SomeType a更改为StateT SomeType m a,保留m。这样,您的函数可以在任何monadic堆栈上工作。对于那些需要IO的函数,您可以指定底部的monad必须是IO:

printState :: MonadIO m => StateT Int m ()
printState = do a <- get
             liftIO $ print a

现在,应该可以同时使用这两个功能:

-- You could use me without IO as well!
subOne :: Monad m => StateT Int m ()
subOne = do a <- get
            put $ a - 1

printState :: MonadIO m => StateT Int m ()
printState = do a <- get
             liftIO $ print a

toZero :: StateT Int IO ()
toZero = do subOne     -- A really pure function
            printState -- function may perform IO
            a <- get
            when (a > 0) toZero
PS:我使用的是GHC 7,其中一些库在中途发生了变化,因此在GHC 6上可能会有所不同。

答案 1 :(得分:3)

更直接地回答您的问题:函数hoist完全按照您更简单的方式执行。用法示例:

import Control.Monad.State
import Data.Functor.Identity
import Control.Monad.Morph

foo :: State Int Integer
foo = put 1 >> return 1

bar :: StateT Int IO Integer
bar = hoist (return . runIdentity) foo

hoistMFunctor类的一部分,其定义如下:

class MFunctor t where
  hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

大多数monad变形金刚都有这种情况,但不是ContT