Top-level state debate on the wiki

Ben Rudiak wrote (snipped):
I put up a wiki page summarizing the main proposals for top-level mutable state. The type-dictionary approach isn't there yet, but there's a space for it; I'll probably fill it in within the next 24 hours unless someone else feels like doing it first.
Please add more detail, objections, examples. Especially examples!
Here's the page:
I have added a summary of the type-dictionary approach. I recommend other people look at this page and, if there is something they disagree with, amend it so that their own view is reflected. IMO the WiKi approach is an excellent way of obtaining consensus and providing an overview of the topic.

Looking at the wiki summary [1] (very good, BTW), I have a question (I've skipped much of the debate, so please just give a message pointer if I missed something). Why does RandomIO need to use the unsafePerformIO hack if its already in the IO monad? BTW, if the goal is to have a random number generator as a pure (non-IO) function, I *do* think there's a reasonable semantic objection here. I'd also like to request that some reference links are added for some of the proposed solutions: 2b - reference to stToIO 3 - reference to Data.Dynamic, and how a dictionary of types can be used to provide global variables. #g -- [1] http://haskell.org/hawiki/GlobalMutableState ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

randomIO needs the unsafePerformIO hack because it does not return the seed... however it can be rewritten: getRandomIO :: Int -> IO (IO Int) getRandomIO x_init = do x <- newIORef x_init return (randomIO x) where randomIO :: IORef Int -> IO Int randomIO r = do -- where f & g generate the pseudo-random sequence x <- readIORef r writeIORef r (f x) return (g x) The difference is in the API to use this version you would have to pass the generator around: main :: IO () main = do rio <- getRandomIO test rio test :: IO Int -> IO () test rio = do x <- rio putStrLn (show x) with randomIO the seed is in a 'global' variable... of course if you want a sequence outside of the IO monad... both versions can be used to generate a lazy sequence... getRandomList :: IO Int -> IO [Int] getRandomList rio = do r0 <- rio rs <- getRandomList rio return (r0:rs) Keean. Graham Klyne wrote:
Looking at the wiki summary [1] (very good, BTW), I have a question (I've skipped much of the debate, so please just give a message pointer if I missed something).
Why does RandomIO need to use the unsafePerformIO hack if its already in the IO monad?
BTW, if the goal is to have a random number generator as a pure (non-IO) function, I *do* think there's a reasonable semantic objection here.
I'd also like to request that some reference links are added for some of the proposed solutions: 2b - reference to stToIO 3 - reference to Data.Dynamic, and how a dictionary of types can be used to provide global variables.
#g --
[1] http://haskell.org/hawiki/GlobalMutableState
------------ Graham Klyne For email: http://www.ninebynine.org/#Contact
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Fri, Dec 03, 2004 at 10:05:08AM +0000, Graham Klyne wrote:
Looking at the wiki summary [1] (very good, BTW), I have a question (I've skipped much of the debate, so please just give a message pointer if I missed something).
Why does RandomIO need to use the unsafePerformIO hack if its already in the IO monad?
The random number state needs to be stored between calls to randomIO, it is global state which right now tends to be implemented via the unsafePerformIO hack. Any of the current global state hacks or the proposals on the Wiki would also suffice to implement it. All of the global state proposals would require access to the state via the IO monad. Which is why I like to think of it as 'extending the world' rather than global variables. IO can be thought of (and is how it is directly implemented in GHC) as functions similar to data World -- no constructors, World is an abstract type -- representing the 'state of the universe' type IO a = World -> (a,World) meaning an IO action that returns a Char is actually a pure function from the World to a new World and the Char. now, imagine we didn't have global variables, then we would have to pass the values of the global variables everywhere, collecting the new variables from the function results. note that this is exactly what the IO monad does! So, all the global variables semantics are completly defined by 'adding' the values of the global variables to World. if World were actually directly implemented, it might look something like: data World = World { keyPressedOnStandardInput :: Maybe Char, theFilesystem :: [(FileName,Contents)], presidentOfTheUnitedStates :: String, currentMoodOfUser :: Mood, -- every other property of the universe ... } (you can see why we like to keep World abstract :)) a global variable is just another entry in the World record. This is why global variables are safe to use in a lazy functional language (perhaps against intuition), their use is confined to the IO monad, which passes around the state of everything (including the global variables) in a purely functional way. The problem is there is just no mechanism in haskell to declare them and it is unclear what said mechanism should look like which is what the whole debate is about :)
BTW, if the goal is to have a random number generator as a pure (non-IO) function, I *do* think there's a reasonable semantic objection here.
Oh yes. no one is wanting that. John -- John Meacham - ⑆repetae.net⑆john⑈

John Meacham wrote:
On Fri, Dec 03, 2004 at 10:05:08AM +0000, Graham Klyne wrote:
....
BTW, if the goal is to have a random number generator as a pure (non-IO) function, I *do* think there's a reasonable semantic objection here.
Oh yes. no one is wanting that.
May I? Sometimes I am surprised how much energy goes into such details as discussed under this (or other) topic, and for weeks *nobody* says a single word about the applications. What for? When used? Personally I never paid too much attention to this monadic Random stuff, since in my applications I could always use PURE FUNCTIONAL usage of RN generators. 1. Using (lazy) streams of random numbers. I needed a noise signal, I produced a noise signal, by iterating a generator. 2. I needed a multidimensional Perlin noise. One localized loop permitted to fill an array with pseudo-random values, and then a "random" f(x,y,z) is obtained by indexing and some intricate combinatorics which decorrelates the values. 3. There exist a category of *ergodic* functions, *PURE* functions which behave erratically when the argument, integer, n= 0, 1, 2, 3, ... It looks like noise, perfectly usable. This has been used by Greg Ward in graphics, and it should be published somewhere in Graphics Gems. This function is based on a polynomial with the bits XORed and truncated to (say) 32 bits. Trivial to do in languages which work with machine integers, ignoring overflow (like Clean). More difficult in Haskell. Jerzy Karczmarczuk
participants (5)
-
George Russell
-
Graham Klyne
-
Jerzy Karczmarczuk
-
John Meacham
-
Keean Schupke