I'm having a slight problem implementing a particle based fluid simulation in Haskell for a programming competition. I currently have an array of particles that gets modified at each simulation step. Each particle is a tuple of 2 vectors: position and velocity (my own Vec3D module). At some point I need to extract the positions from the particles (sort of like unzipping lists) which I tried to do like this:
let xs = runSTArray $ do
xs' <- newArray (min, max) (0.0,0.0,0.0) :: ST s (STArray s Int Vec3D)
forM_ [min..max] $ \j -> do
(x, v) <- readArray ps' j
writeArray xs' j x
return xs'
let displacements = doubleDensityRelaxation xs restDen k kNear t h
where ps'
and doubleDensityRelaxation
are of type
type Vec3D = (Double, Double, Double)
ps' :: ST s (STArray s Int (Vec3D, Vec3D))
doubleDensityRelaxation :: Array Int Vec3D -> Double -> Double -> Double -> Double -> Double -> Array Int Vec3D
so xs
should be of type xs :: Array Int Vec3D
. However, I get
Simulator.hs:76:35:
No instance for (MArray (STArray s) (Vec3D, Vec3D) (ST s1))
arising from a use of `readArray'
Possible fix:
add an instance declaration for
(MArray (STArray s) (Vec3D, Vec3D) (ST s1))
In a stmt of a 'do' block: (x, v) <- readArray ps' j
In the expression:
do { (x, v) <- readArray ps' j;
writeArray xs' j x }
In the second argument of `($)', namely
`\ j
-> do { (x, v) <- readArray ps' j;
writeArray xs' j x }'
from the compiler which I dont really understand given that readArray
isn't supposed to return an entire array; just one (Vec3D, Vec3D)
element.
As a fix, could I make doubleDensityRelaxation
take ST s (STArray s Int Vec3D)
directly?
If I change the type like that and remove the let xs = runSTArray $ do
part I get
Couldn't match expected type `ST s0 (STArray s0 Int Vec3D)'
with actual type `STArray s Int Vec3D'
but if I give it (ST s xs')
as an input instead of just xs'
it complains about data constructor ST
not being in scope. My imports are currently
import Data.List
import Data.Array
import Data.Array.ST
import Control.Monad
import Control.Monad.ST
import Vec3D
Complete function:
step :: Array Int (Vec3D, Vec3D) -> Vec3D -> Double -> Double -> Double -> Double -> Double -> Array Int (Vec3D, Vec3D)
step ps g restDen k kNear t h = runSTArray $ do
ps' <- thaw ps :: ST s (STArray s Int Particle)
--GRAVITY
forM_ [min..max] $ \i -> do
(x, v) <- readArray ps' i
writeArray ps' i (x, addGravity v g t)
--TODO - VISCOSITY
--MOVE
xsOld <- newArray (min, max) (0.0,0.0,0.0) :: ST s(STArray s Int Vec3D)
forM_ [min..max] $ \i -> do
(x, v) <- readArray ps' i
writeArray xsOld i x
writeArray ps' i (x `add` (v `mulSc` t), v)
--TODO - SPRINGS
--DOUBLE DENSITY RELAXATION
xs' <- newArray (min, max) (0.0,0.0,0.0) :: ST s (STArray s Int Vec3D)
forM_ [min..max] $ \j -> do
(x, v) <- readArray ps' j
writeArray xs' j x
let displacements = doubleDensityRelaxation (freeze xs') restDen k kNear t h
ps <- newArray (min, max) ((0.0,0.0,0.0), (0.0,0.0,0.0)) :: ST s (STArray s Int (Vec3D, Vec3D))
--TODO incomplete
return ps
where
addGravity v g t = v `add` (g `mulSc` t)
(min, max) = bounds ps