如何创建一个使用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用于控件结构。
答案 0 :(得分:6)
MonadReader
类型的类takes only one parameter与MonadState
和MonadCont
不同。由于该参数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变压器。)