2011-03-16 78 views
1

假設我有這樣的事情:monad變壓器中的內部monad是否有`replicateM`函數?

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) 

我就要同類型的lift困惑和replicateM。有沒有一種組合可以在變壓器內複製單芯片State MyState

在未來,我會因此最好把事情有這個怪物類型:(前右更換ReaderT Environment (State MyState) ReportReaderT Environment (StateT MyState (Rand StdGen)) Report

編輯:一個側面的問題 - 是否有比使用ReaderT Environment (State MyState) Report更好的策略?

+0

使用ReaderT和StateT看起來合理的策略。爲了實際使用,我建議不要直接使用「請求,獲取,放置」,使用描述性名稱定義一個簡短的別名或助手,然後使用它。這允許您編輯Monad堆棧的實現,並且只需要更新幫助器。 – 2011-03-16 16:00:45

回答

4

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 

注意,我刪除了 「升降機」,因爲ReaderT有MonadState pass-通過實例。運行FOO曾經給:

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

我可以連續運行富七次:

*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) 

在什麼上面需要更多的澄清?

+0

哼哼......現在我看到了混亂的根源。我在想,如果我做了'replicateM n foo',我會得到一個'ReaderT環境[(狀態MyState)報告]'。現在我發現這顯然不是這種情況。該類型甚至沒有意義... – 2011-03-16 16:05:37

+0

您是如何擺脫GHCi中模塊「Control.Monad.State」的歧義的? (我有包mtl和monads-tf) – ony 2011-03-16 16:08:01

+0

@ony你可以使用'ghci -XPackageImports ...'和'import'mtl「Control.Monad.State'或'ghci -package mtl ...' – 2011-03-16 16:22:14

2

有時它足以證明類型,如果你不確定的方式來使用的東西

-- 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]