Andrew J Bromage writes: >> John Hughes wrote a nice pearl on the subject, see >> >> http://www.math.chalmers.se/~rjmh/Globals.ps > >Nice!
I do not think it is nice: I do not like any of the solutions Hughes considers in that paper because this problem can be handled much more simply with lexical scope and the IO monad. Just to get our bearings, let us first consider the solution that uses unsafePerformIO, which neither Hughes nor I prefer: >globalVar :: IORef Int >globalVar = unsafePerformIO $ newIORef 0 >foo = fff aaa bbb ccc >bar = ggg xxx yyy zzz >main = mmm >> nnn >> ooo where the lines >foo = fff aaa bbb ccc >bar = ggg xxx yyy zzz stand in for a typically much larger chunk of code --the bulk of the program, let us call it. The solution I prefer replaces that last with >main=do > globalVar<-newIORef 0 > let > foo = fff aaa bbb ccc > bar = ggg xxx yyy zzz > mmm >> nnn >> ooo In other words, to be painfully explicit, the solution I prefer arranges the program so that (1) the global variable is the result of an IO computation just like every other IO computation; and (2) the global variable has a lexical scope that extends over the bulk of the program. It strikes me as a simple and obvious application of lexical scope, and I am surprised that it received no mention in the discussions on this list and in Hughes's paper. Of course, whenever you want to read or to write my global variable, you must be in the IO monad, but Hughes's solution requires being in a state monad. I do not consider the IO monad any worse than any other state monad. Am I the only one who prefers the above "lexical scope" solution to all the solutions in Hughes's paper and given previously on this list? Indentation One may raise the following objection to the "lexical scope" solution: levels of indentation are a scarce resource and a solution that consumes two of those levels before the program proper even starts is wasteful. I do not disagree with that objection; but I believe that the best response to the objection is not to abandon the the "lexical scope" solution but rather to adjust the syntactical definition of Haskell and of the do notation. E.g., we can eliminate one level of indentation by doing what GHCi does and eliminate the requirement for the "main=do" in programs. (This has the added benefit of shortening the Haskell version of "hello, world" to putStrLn "hello, world." Do not underestimate the attractiveness of a language with a short "hello, world" to the more practically-inclined programmers of the world.) >Why isn't RefMonad in hslibs? >It makes perfect sense for there to be more than one kind of "ref" >for a given monad. Indeed, sometimes it's important. Quite often, I >use a custom ref built on top of IORef which supports Ord, as this is >needed for hash consing. I think it is cleaner and simpler to ask the compiler maintainers to add an IORef instance to Ord. They know better how to implement it so it is fast. And it is the solution that puts the least cognitive demmand on readers of your program. (It's the easiest to learn, I mean.) I am not unalterably opposed to class RefMonad or to implicit variables. If someone makes a convincing argument that they are the best solution to an issue or problem, I will use them. But Hughes's paper does not convince me. Note that the global-variable solution I prefer will be more familiar to non-Haskell programmers. (To appreciate it, they have to "grok" monads, which can be a high hurdle, but they have to "grok" monads to appreciate Hughes's solution, too.) I wonder if Hughes's solution was motivated by a desire to avoid having to stay in the IO monad during all access to global variables. Several on this list have stated or implied that the IO monad is something to be resisted when possible. I do not agree with that position. But a general defense of the IO monad will take much more time than I have today. _______________________________________________ Haskell-Cafe mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/haskell-cafe