代码之家  ›  专栏  ›  技术社区  ›  dopamane

如何使用statet、contt和readert创建monad?

  •  2
  • dopamane  · 技术社区  · 7 年前

    如何创建一个使用状态、控制和读卡器变压器的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 需要种类 * -> * ?…我沉溺于各种类型,需要解释。什么形式 暂停 必须接受,一个功能?Contt如何整合?最后,我计划使用cont作为控制结构。

    1 回复  |  直到 7 年前
        1
  •  6
  •   bergey    7 年前

    不像 MonadReader MonadState , the MonadCont 类型类 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 }
    

    请注意 r 在你的定义中 newtype M r 作为决赛通过( a 参数到 康特 . 插入变量,你有

    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变压器。)

    推荐文章