如何使用StateT,ContT和ReaderT创建monad?

时间:2018-11-20 23:11:27

标签: haskell monads monad-transformers continuations

如何创建一个使用State,Cont和Reader转换器的monad?我想阅读一个环境,并更新/使用状态。但是,我也想暂停/中断操作。例如,如果满足条件,则状态保持不变。

到目前为止,我有一个使用ReaderT和StateT的monad,但我无法弄清楚如何包含ContT:

<img src="jags2.png" alt="jaguar" style="left: 50%; position: absolute;">

出现错误:

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Test where
-- monads
import   Data.Functor.Identity (Identity, runIdentity)
import   Control.Monad.State
import   Control.Monad.Reader
import   Control.Monad.Cont

-- reader environment
type In = Integer

-- cont: if true then pause, else continue 
type Pause = Bool

-- state environment:
newtype StateType = StateType { s :: Integer }

newtype M r = M {_unM :: ReaderT In (ContT Pause (StateT StateType Identity)) r}
  deriving ( Functor, Applicative, Monad
           , MonadReader In
           , MonadCont   Pause
           , MonadState  StateType
           )

-- run monadic action
runM :: In -> Pause -> StateType -> M r -> StateType
runM inp pause initial act
  = runIdentity             -- unwrap identity
  $ flip execStateT initial -- unwrap state
  $ flip runContT   pause   -- unwrap cont
  $ flip runReaderT inp     -- unwrap reader
  $ _unM act                -- unwrap action

好吧,但是为什么* Expected kind `* -> *', but `Pause' has kind `*' * In the first argument of `MonadCont', namely `Pause' In the newtype declaration for `M' | 24| , MonadCont Pause | 需要种类Pause?...我淹没在类型中,需要解释。 * -> *必须采用什么形式的函数? ContT如何整合?最终,我计划将Cont用于控件结构。

1 个答案:

答案 0 :(得分:6)

MonadReader类型的类takes only one parameterMonadStateMonadCont不同。由于该参数m必须是Monad,因此它必须具有种类* -> *

在派生子句中,您希望MonadCont,而不是MonadCont Pause

添加为回答后续问题:

ContT is defined as:

newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r }

请注意,您在r的定义中将newtype M r作为最终(a)参数传递到ContT。插入变量,就可以了

ContT Bool (State StateType) a = ContT { 
    runContT :: (a -> State StateType Bool) -> (State StateType Bool)
  }

这提供了一个计算上下文,您可以在其中操纵StateType,并使用定界的延续。最终,您将构造一个ContT Bool (State StateType) Bool。然后,您可以运行延续(使用evalContT),并返回到更简单的State StateType上下文。 (实际上,您可以在程序的同一部分中解开所有3个monad变压器。)