
testfunc = do r <- newSTRef ('x',0) foo r bar r (c,n) <- readSTRef r return n
Jorge Adriano
Yeap, I could do it like this myself :) The whole problem is with passing the 'r' as a parameter, which is precisly what I'm trying to avoid.
I agree with you. My work-around is then to define foo and bar locally to testfunc, in the scope of r: testfunc = do r <- newSTRef ('x',0) let foo = do (c,n) <- readSTRef r writeSTRef r ('a', n+1) bar = do (c,n) <- readSTRef r writeSTRef r (c,n+2) foo bar (c,n) <- readSTRef r return n But if this looks like unsatisfactory (it does to me, too), perhaps you have to go back to DIY monads. DIY monads are good when: you fix the state variables, you don't want to mention them in subprogram parameters. The ST monad is good when: you create more state variables on the fly, you use mutable arrays, you don't want to write your own monad and put/get commands.

I agree with you. My work-around is then to define foo and bar locally to testfunc, in the scope of r:
testfunc = do r <- newSTRef ('x',0) let foo = do (c,n) <- readSTRef r writeSTRef r ('a', n+1) bar = do (c,n) <- readSTRef r writeSTRef r (c,n+2) foo bar (c,n) <- readSTRef r return n
Thought about that to... but it looks kind of... terribly ugly (sorry :)
But if this looks like unsatisfactory (it does to me, too), perhaps you have to go back to DIY monads. DIY? what does that means?
DIY monads are good when: you fix the state variables, you don't want to mention them in subprogram parameters. Yeap!
The ST monad is good when: you create more state variables on the fly, you use mutable arrays, you don't want to write your own monad and put/get commands.
What if you want both and keep nice clean(*) programming style... :-) J.A. (*) Clean as in "not dirty", not Clean the FL.

DIY? what does that means?
Do It Yourself. I.e. as in my tutorial.
What if you want both and keep nice clean(*) programming style... :-)
You can compose monads. I've done something like the following in the past (only with IO): data StateTrans s a = StateTrans (s -> ST (s,a)) Here s is the global state. A function that changes the global state f :: s -> s can be lifted into the monad by listGlobalMutator :: (s -> s) -> StateTrans s a liftGlobalMutator f = StateTrans (\s -> return (f s, ())) similarly liftGlobalAccessor :: (s -> a) -> StateTrans s a liftGlobalAccessor g = StateTrans (\s -> return (s, g s)) and liftST :: ST a -> StateTrans s a liftST st = StateTrans (\s -> do { a<- st ; return (s, a)}) This gives you a fixed global state (which could be a tuple of global variables) and as many dynamic variables (accessed via references) as you want. Probably I should have used a strict pair type above instead of (,). Cheers, Theo Norvell

DIY monads are good when: you fix the state variables, you don't want to mention them in subprogram parameters.
I've taken this solution for a fairly large piece of software. One word of warning about DIY state monads, you have to be very carefull about strictness and lazyness. If your monad or state are at all lazy, you can end up dragging a lot of old states around. When you construct a new state, you want to be sure that it contains no unevaluated references to a previous state! Cheers, Theodore Norvell ---------------------------- Dr. Theodore Norvell theo@engr.mun.ca Electrical and Computer Engineering http://www.engr.mun.ca/~theo Engineering and Applied Science Memorial University of Newfoundland St. John's, NF, Canada, A1B 3X5 Currently visiting the Department of Computer Science and ICICS at the University of British Columbia. See my webpage for contact details.
participants (4)
-
Albert Lai
-
Jorge Adriano
-
Theodore Norvell
-
Theodore Norvell