如何使用 StateT、ContT 和 ReaderT 创建 monad?
How to create a monad using StateT, ContT, and ReaderT?
如何创建使用 State、Cont 和 Reader 转换器的 monad?我想读一个环境,和 update/use 状态。不过,我还要pause/interrupt这个动作。比如满足一个条件,状态不变。
到目前为止,我有一个使用 ReaderT 和 StateT 的 monad,但我不知道如何包含 ContT:
{-# 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
需要类型 * -> *
?...我被类型淹没了,需要解释。 Pause
必须采用什么形式,函数? ContT如何整合?最终,我打算使用 Cont 作为控制结构。
与 MonadReader
和 MonadState
不同,MonadCont
类型 class takes only one parameter。由于该参数 m
必须是 Monad
,因此它必须具有种类 * -> *
.
在您的派生子句中,您希望 MonadCont,
而不是 MonadCont Pause
。
为回答后续问题而添加:
ContT
is defined as:
newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r }
请注意,newtype M r
定义中的 r
作为最终 (a
) 参数传递给 ContT
。插入变量,你有
ContT Bool (State StateType) a = ContT {
runContT :: (a -> State StateType Bool) -> (State StateType Bool)
}
这提供了一个计算上下文,您可以在其中操作 StateType
并使用定界延续。最终,你会构造一个ContT Bool (State StateType) Bool
。然后你可以 运行 继续(使用 evalContT
),return 到更简单的 State StateType
上下文。 (实际上,您可以在程序的同一部分解包所有 3 个 monad 转换器。)
如何创建使用 State、Cont 和 Reader 转换器的 monad?我想读一个环境,和 update/use 状态。不过,我还要pause/interrupt这个动作。比如满足一个条件,状态不变。
到目前为止,我有一个使用 ReaderT 和 StateT 的 monad,但我不知道如何包含 ContT:
{-# 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
需要类型 * -> *
?...我被类型淹没了,需要解释。 Pause
必须采用什么形式,函数? ContT如何整合?最终,我打算使用 Cont 作为控制结构。
与 MonadReader
和 MonadState
不同,MonadCont
类型 class takes only one parameter。由于该参数 m
必须是 Monad
,因此它必须具有种类 * -> *
.
在您的派生子句中,您希望 MonadCont,
而不是 MonadCont Pause
。
为回答后续问题而添加:
ContT
is defined as:
newtype ContT r m a = ContT { runContT :: (a -> m r) -> m r }
请注意,newtype M r
定义中的 r
作为最终 (a
) 参数传递给 ContT
。插入变量,你有
ContT Bool (State StateType) a = ContT {
runContT :: (a -> State StateType Bool) -> (State StateType Bool)
}
这提供了一个计算上下文,您可以在其中操作 StateType
并使用定界延续。最终,你会构造一个ContT Bool (State StateType) Bool
。然后你可以 运行 继续(使用 evalContT
),return 到更简单的 State StateType
上下文。 (实际上,您可以在程序的同一部分解包所有 3 个 monad 转换器。)