表示通过输入更新状态的最佳方式是什么?
我模拟物理系统。它有状态(坐标,速度)。状态由模拟更新,该模拟从stdin
获取一些参数(力)。在每个模拟周期后,结果将转到stdout
。
程序应在N个循环后停止。
我已经使用readIORef
和writeIORef
完成了这项工作,但这很难看。
答案 0 :(得分:5)
执行此操作的一种简单方法是沿着惰性(可能无限)列表进行调整,而不是执行任何显式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
答案 1 :(得分:2)
您使用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。