RE: [Haskell] threading mutable state through callbacks
On 13 October 2004 03:36, Wolfgang Thaller wrote:
b) Some predetermined order, with semantics like mdo:
John Meacham wrote:
The basic idea is that your entire program behaves as if in a giant 'mdo' block, ordered in module dependency order.
I also like the mdo idea - in fact it occurred to me yesterday, but I wasn't sure whether there would be any gotchas when the details were worked out, and it looks like John has established that things work out nicely. GHC already has an initialisation procedure for each module in the program which could be adapted to run the initialisation-time IO actions, with a little effort. I'm more worried about what other changes we have to make to the compiler: if we can avoid having to flag top-level bindings as monadic/non-monadic all the way through the compiler, then we could avoid a pervasive change to the compiler. At the moment I can't see an obvious way to do that.
What is module dependency order? There's no such thing when there are circular dependencies, and when there aren't any, it might still depend on the order of import directives, which is probably not something I want program semantics to depend on. I feel that In a large program, you'll probably get more surprises from this. The good thing is that you can always use unsafeInterleaveIO to get the other semantics back, so we should probably investigate this further.
GHC's init blocks are run in dependency order, picking an arbitrary depth-first traversal when there's a recursive module dependency. Seems as good a choice as any. Cheers, Simon
On Wed, Oct 13, 2004 at 03:34:07PM +0100, Simon Marlow wrote:
On 13 October 2004 03:36, Wolfgang Thaller wrote:
b) Some predetermined order, with semantics like mdo:
John Meacham wrote:
The basic idea is that your entire program behaves as if in a giant 'mdo' block, ordered in module dependency order.
I also like the mdo idea - in fact it occurred to me yesterday, but I wasn't sure whether there would be any gotchas when the details were worked out, and it looks like John has established that things work out nicely.
GHC already has an initialisation procedure for each module in the program which could be adapted to run the initialisation-time IO actions, with a little effort.
I'm more worried about what other changes we have to make to the compiler: if we can avoid having to flag top-level bindings as monadic/non-monadic all the way through the compiler, then we could avoid a pervasive change to the compiler. At the moment I can't see an obvious way to do that.
I was thinking that all that would need to be done is a rewriting of fooVar <- newIORef 42 barVar <- newIORef 3 to fooVar = error "Loop detecting in binding of fooVar" barVar = error "Loop detecting in binding of barVar" _init_ = do ... x <- newIORef 42 veryUnsafeUpdate# fooVar x y <- newIORef 3 veryUnsafeUpdate# barVar y ... where veryUnsafeUpdate# :: a -> a -> IO () replaces its first argument with an indirection to its second argument. (this is very unsafe, so probably shouldn't be exposed, but should be easy enough inside the compiler) other than than one call to veryUnsafeUpdate#, global bindings can be treated exactly like CAFs. The only tricky things are we need to typecheck before carying out this translation (to get the right monomorphic types for fooVar and barVar) and ensure they remain CAFs (which a NOINLINE note should acomplish, but even might not be needed if we include the _init_ routine in the optimization as then the routines will be called from more than one place). we no longer need to worry about the CSE problem either if we make sure the error messages are distinct (which they will be if we include the file/line number) == Another idea == A useful addition to ghc would be an ability to register exit handlers which are run after main exits. then this gives us a nice general initialization/finalization framework for modules for free.. like _ <- do global initialization _ <- onExit $ do global finalization == Another thought == We should come up with some consistent terminology for this extension, I keep on having to think about it and sometimes change mid-paragraph :) I was thinking if a = let b = ... in ... c <- do d <- ... ... then a - global declaration b - local declaration c - global binding d - local binding for consistency, perhaps something bound by a lambda should be called a lambda binding. does this terminology make sense? perhaps there is another more obivous one? any suggestions? John -- John Meacham - ⑆repetae.net⑆john⑈
participants (2)
-
John Meacham -
Simon Marlow