Как создать монаду с помощью StateT, ContT и ReaderT? - PullRequest
0 голосов
/ 21 ноября 2018

Как мне создать монаду, которая использует преобразователи State, Cont и Reader?Я хотел бы прочитать окружение и обновить / использовать состояние.Тем не менее, я также хотел бы приостановить / прервать действие.Например, если условие выполнено, состояние остается неизменным.

Пока у меня есть монада, использующая ReaderT и StateT, но я не могу понять, как включить 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 для структуры управления.

1 Ответ

0 голосов
/ 21 ноября 2018

В отличие от MonadReader и MonadState, класс MonadCont типа принимает только один параметр .Так как этот параметр m должен быть Monad, он должен иметь вид * -> *.

. В своем предложении вы хотите, чтобы MonadCont, не MonadCont Pause.

было добавлено вОтвет на следующий вопрос:

ContT определяется как:

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 ваших монадных трансформатора в одной и той же части вашей программы.)

...