表示通过输入更新状态的最佳方式是什么?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