Существует ли функция `replicateM` для внутренней монады в монадном преобразователе? - PullRequest
1 голос
/ 16 марта 2011

Предположим, у меня что-то вроде этого:

data Environment = ...
data MyState = ...
data Report  = ...

updateState :: Environment -> MyState -> MyState
updateState = ...

report :: MyState -> Report
report = ...

foo :: ReaderT Environment (State MyState) Report 
foo = do env   <- ask
         state <- lift get
         let newState = updateState env state
         lift $ put newState
         return $ report newState

Что у меня в голове - это моделирование процесса времени, в котором у меня есть параметры, которые будут сохранены в Environment, динамическое состояние будет сохранено вMyState и информация, которую я хочу собирать на каждом шаге симуляции, будет храниться в Report.

Теперь я не хочу выполнять много шагов симуляции и получать список с отчетамиза каждый шаг по времени.

Я обычно делал это без ReaderT и использовал для передачи таких параметров:

 foo :: Enviroment -> State MyState Report

Тогда я бы просто сделал:

 manySteps :: Int -> Enviroment -> State MyState [Report]
 manySteps n env = replicate n $ (foo env) 

I 'я путаюсь с типами lift и replicateM.Есть ли комбинация, которая повторяла бы монаду State MyState внутри трансформатора?

В будущем я заменим ReaderT Environment (State MyState) Report на ReaderT Environment (StateT MyState (Rand StdGen)) Report, так что лучше все сделать правильно, прежде чем использовать этот тип монстра :(.

edit: в качестве дополнительного вопроса - есть ли лучшая стратегия, чем использование ReaderT Environment (State MyState) Report?

Ответы [ 2 ]

4 голосов
/ 16 марта 2011

Конкретный пример replicateM здесь:

import Control.Monad
import Control.Monad.Reader
import Control.Monad.State

data Environment = E Int deriving Show
data MyState = S Int deriving Show
data Report  = R String deriving Show

updateState :: Environment -> MyState -> MyState
updateState (E step) (S val) = S $! val + step

report :: MyState -> Report
report (S val) = R (show val)

foo :: ReaderT Environment (State MyState) Report 
foo = do env   <- ask
         state <- get -- lift was not needed
         let newState = updateState env state
         put newState -- lift was not needed
         return $ report newState

run e s m = runState (runReaderT m e) s

Обратите внимание, что я удалил "lift", так как ReaderT имеет экземпляр сквозного доступа MonadState. Запуск foo один раз дает:

*Main> run (E 10) (S 5) foo
(R "15",S 15)

Я могу запустить foo семь раз подряд:

*Main> run (E 10) (S 5) (replicateM 7 foo)
([R "15",R "25",R "35",R "45",R "55",R "65",R "75"],S 75)

Что в вышесказанном нуждается в уточнении?

2 голосов
/ 16 марта 2011

Иногда достаточно доказать тип, если вы не знаете, как использовать что-то

-- import Control.Monad.State
import Control.Monad
import Control.Monad.Trans.Reader

data Environment
data MyState
data Report
data State a b
instance Monad (State a)

foo = undefined :: ReaderT Environment (State MyState) Report

Чем в GHCi

*Main> :t flip replicateM foo
flip replicateM foo
  :: Int -> ReaderT Environment (State MyState) [Report]
...