module Nodes() where
import Control.Monad.State
import Control.Monad.ST
import Data.STRef
-- The Monad is a composition of a state monad that tracks the Nodes s
-- network, and the ST Monad used for mutable references.
-- FIXME: optimization: put nodes in an unboxed array and use integers instead of refs.
type Value = Double -- Let's keep things simple for now.
data Node s = Node (STRef s (Maybe Value, [Equation s]))
type Solver s = [Node s] -> ST s (Int,Int)
data Equation s = Equation (Solver s) [Node s]
data Network s = Network [Node s] [Equation s]
-- Something I don't quite understand fully is how to mix functional
-- and imperative parts once you're working inside an ST monad.
-- I.e. does it make sense to use State to thread state while in ST?
-- I think the answer is yes: State allows *implicit* state, while ST
-- only allows for references and sequential ops. (I.e. it's too
-- simple to use the word "state" to mean anything in general. There
-- are different kinds of state..)
-- I'm struggling with doing this ST/State combination properly so I'm
-- going to stick with explicit references of the network. This might
-- also make combining networks a bit simpler.
newNetwork :: ST s (STRef s (Network s))
newNetwork = newSTRef $ Network [] []
newNode net = do
n <- newSTRef (Nothing, [])
modifySTRef net $ (\(Network ns es) -> Network (ns ++ [Node n]) es)
return $ Node n
newNodes net n =
forM [1..n] $ (\_ -> newNode net)
newEquation net solver ns = do
let e = Equation solver ns in do
modifySTRef net $ (\(Network ns es) -> Network ns (e:es))
return e
nodes nw = do
Network ns _ <- readSTRef nw
forM ns $ \(Node r) -> do
(v, _) <- readSTRef r
return v
input (Node n) v = modifySTRef n $ \(_, e) -> (Just v, e)
solve (Equation s ns) = s ns
{-
sumSolver ns = do
acc = newSTRef Nothing
forM ns $ \r -> do
v <-
-}
test = runST $ do
nw <- newNetwork
[n1,n2,n3] <- newNodes nw 3
input n1 1
input n2 2
eq <- newEquation nw sumSolver [n1,n2,n3]
solve eq
nodes nw