【发布时间】:2019-04-23 11:41:53
【问题描述】:
如何创建一个使用 State、Cont 和 Reader 转换器的 monad?我想阅读一个环境,并更新/使用状态。但是,我也想暂停/中断动作。例如,如果满足某个条件,则状态保持不变。
到目前为止,我有一个使用 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 用于控制结构。
【问题讨论】:
-
一些随机的 cmets:你“堆叠”monad 转换器的顺序有时(通常)很重要。我看不出来你说的对不对。无论如何,
ContT Pause是ContT Bool,它看起来有点奇怪,因为它是(a -> m Bool) -> m Bool,这可能是也可能不是你想要的。 -
@chi 在堆栈排序方面,我想“读取”一个整数,如果整数是奇数,则不会发生状态更新,如果偶数则将其添加到状态(累加器)。这就是为什么我将它们堆叠起来,
ReaderT (ContT (StateT)))。可能不正确,一直在阅读文档以确认。关于ContT Bool,我认为这是我困惑的根源。我最初将其视为ReaderT或StateT,它们分别使用In和StateType。(a -> m Bool) -> m Bool是什么?似乎比StateType或 Reader 环境类型更抽象。ContT如何使用runM中的功能?
标签: haskell monads monad-transformers continuations