Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell monad for simulation

Tags:

haskell

What is the best way to represent state updated by input?

I simulate physical system. It has state (coordinates, velocities). State is updated by simulation that takes some parameters (forces) from stdin. Result goes to stdout after each simulation cycle.

Program should stop after N cycles.

I've done it with readIORef and writeIORef but this is ugly.

like image 426
Aleksandr Pakhomov Avatar asked Feb 28 '26 21:02

Aleksandr Pakhomov


2 Answers

One simple way to do this would be brachiating along a lazy (possibly infinite) list instead of doing any explicit 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
like image 157
leftaroundabout Avatar answered Mar 03 '26 10:03

leftaroundabout


You an write this at a very high-level using pipes. First, I will assume that you have already defined the following types, values, and functions:

data Status = Status deriving (Show)
data Param = Param deriving (Read)

initialState :: Status
initialState = undefined

update :: Status -> Param -> Status
update = undefined

numCycles :: Int
numCycles = undefined

Now here comes the pipes code:

import Pipes
import qualified Pipes.Prelude as P

main = runEffect $
    P.readLn >-> P.take numCycles >-> P.scan update initialState id >-> P.print

You can read this as a data processing pipeline from left to right:

  • P.readLn reads input parameters from standard input. It will halt if you reach end of input
  • P.take numCycles only allows up to numCycles parameters to pass through
  • P.scan runs your simulation using the provided initial state and update function and then streams each intermediate state further downstream
  • P.print prints out each intermediate state

To learn more about the pipes library, you can read the official pipes tutorial.

like image 43
Gabriella Gonzalez Avatar answered Mar 03 '26 11:03

Gabriella Gonzalez



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!