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