Haskell monad用于模拟

时间:2014-01-06 21:57:47

标签: haskell

表示通过输入更新状态的最佳方式是什么?

我模拟物理系统。它有状态(坐标,速度)。状态由模拟更新,该模拟从stdin获取一些参数(力)。在每个模拟周期后,结果将转到stdout

程序应在N个循环后停止。

我已经使用readIORefwriteIORef完成了这项工作,但这很难看。

2 个答案:

答案 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