表示通過輸入更新狀態的最佳方式是什麼?Haskell monad用於模擬
我模擬物理系統。它有狀態(座標,速度)。狀態通過模擬進行更新,該模擬需要來自stdin
的一些參數(力)。結果在每個模擬週期結束後變爲stdout
。
程序應該在N個週期後停止。
我已經完成了readIORef
和writeIORef
,但這很醜陋。
表示通過輸入更新狀態的最佳方式是什麼?Haskell monad用於模擬
我模擬物理系統。它有狀態(座標,速度)。狀態通過模擬進行更新,該模擬需要來自stdin
的一些參數(力)。結果在每個模擬週期結束後變爲stdout
。
程序應該在N個週期後停止。
我已經完成了readIORef
和writeIORef
,但這很醜陋。
這樣做的一個簡單方法是沿着一個懶惰的(可能是無限的)列表,而不是做任何明確的IO。
import Control.Monad.State
-- Prerequisites:
data SimState -- coordinates & velocities.
data SimTVParams -- what's read from input. `instance Read`.
initialState :: SimState
simStep :: SimTVParams -> SimState -> SimState
simStateInfo :: SimState -> String
-- How to do the simulation:
main :: IO()
main = interact $
unlines . map simStateInfo
. simulate initialState
. map read . lines
simulate :: SimState -> [SimTVParams] -> [SimState]
simulate iState = (`evalState` iState) . mapM (state . step)
where step params oldState = (newState, newState)
where newState = simStep params oldState
您可以使用pipes
以非常高的級別編寫此代碼。首先,我會假設你已經定義了以下幾種類型,價值和功能:
data Status = Status deriving (Show)
data Param = Param deriving (Read)
initialState :: Status
initialState = undefined
update :: Status -> Param -> Status
update = undefined
numCycles :: Int
numCycles = undefined
現在,這裏是管道代碼:
import Pipes
import qualified Pipes.Prelude as P
main = runEffect $
P.readLn >-> P.take numCycles >-> P.scan update initialState id >-> P.print
你可以看這是從數據處理管道從左到右:
P.readLn
從標準輸入讀取輸入參數。如果達到輸入P.take numCycles
的端會停止只允許多達numCycles
參數通過P.scan
使用所提供的初始狀態和更新函數運行你的模擬,然後流更下游P.print
打印每一箇中間狀態出每個中間狀態要了解關於pipes
庫的更多信息,可以閱讀official pipes
tutorial。
謝謝。 N步後它不會退出。但是我可以通過stdin通過stdin-n N來做到這一點。 –
沒錯。停止'eof'而不是固定數量的步驟對於這樣的任務來說更自然。 – leftaroundabout