On Wed, Nov 24, 2004 at 11:38:42PM +0000, Ben Rudiak-Gould wrote: > John Meacham wrote: > > >With my mdo proposal, and I think all proposals brought forth, the > >module system behaves identically to how it normally does for > >namespace control. [...] modules do not change code at all, they > >are pure syntantic sugar for deciding what names you can see. > > I'm not sure I understand your mdo proposal correctly then. A lot of > this debate has been over what should happen when a module has a > top-level action like > > x <- putStrLn "hello" > > Everyone agrees that "hello" should be printed at most once, and that if > the value of x is ever demanded, it should be printed exactly once. But > there's disagreement on everything else. What if I import the module > containing the above declaration, but it can be proven statically that > the value of x will never be demanded? What if it can't be proven > statically, but it happens to be true on a particular run? If "hello" is > printed even when x's value is not demanded, then import does more than > bring names into scope: it also sometimes adds things to the top-level > mdo. If "hello" is printed only when x's value is demanded, then import > is okay but the <- construct is unsafe (though safer than unsafePerformIO).
There is some debate about this, and I think this is part of why there is so much confusion about what top-level-initializers are. First of all, I should say that I belive that stylistically x <- putStrLn "Hello" is a bad idea. it is just bad form to put observable actions in initializers IMHO, However, this does not necessarily mean it should be disallowed, because technically, there is nothing wrong with it. I think this causes problems because some people would like haskell to enforce good style, while at the moment I think it would be best to worry about technical problems. style can be enforced by libraries and command line switches to turn on-off features. 'unsafePerformIO' and unboxed types are not exported to the user by default because they probably don't need them and their use is in some sense bad styles. this doesn't mean they should be elided from the language, in fact, they are vital to many of the libraries internals and being able to write your own libraries as fast as system libraries is a necessary feature in any modern language. Now, my mdo proposal as written would have "hello" outputed exactly once at module start up time no matter what, whether x is demanded or not. it is equivalant to a program transformation that collects all the top level initializers and declarations, puts them all in a mdo block and runs it with the semantics explained in the fixIO paper. (with a deterministic, but partially undefined order) an argument can be made for changing it such that the IO action is only exectuted if its value is ever demanded, emulating the current unsafePerformIO hack. this is strictly less powerful than the above semanics, but some people like it better because in some sense the activity is not hidden and it preserves the non-trivial property that importing a module cannot change the programs behavior. (conversly, it does not allow imported modules to change programs behavior, which might be a useful feature for a special purpose debugging library which needs to do some setup for example) Personally, it does not matter too much which semantics are taken, as all my examples would work the same either way as will what I expect 99.99% of the uses of this feature. My guess is that it will come down to what is easier to implement for the compiler. the lazy IO has a lot of the same problems as the unsafePerformIO hack, but it at least offloads them to the compiler internals which can hopefully deal with them better. I think the mdo proposal would be ultimatly cleaner for a compiler writer and its semantics are better defined. the order actions are run while partially undefined is fixed at compile time, as opposed to depending on evaluation order. Also, the mdo way has the advantage of a known valid and implementable semantics rather than just the 'promise of the compiler' it won't do unsafe transformations in the lazy IO case. > This kind of thing turned a lot of people off to the idea of top-level > initialization actions. George Russell's proposal is appealing because > it neatly avoids such problems. With one problem. His proposal cannot be implemented (efficiently) without top-level initialization actions. It is a potential user of TLIs, and very well might be the prefered interface for some but it is not a replacement. Just declaring it is done in the library by the system doesn't really avoid the issue when we are the ones writing the library and compiler too :) John -- John Meacham - ârepetae.netâjohnâ _______________________________________________ Haskell mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell