
Adrian Hey wrote:
Jules Bean wrote:
I've pretty much convinced it's wrong. There should be one and only one "main" from which all subsequent IO activity derives. But creating internal state in the form of mutable data structures is not an IO activity. It just so happens that at the moment the only way to do this is newIORef :: a -> IO(IORef a), but this need not be so (readIORef and writeIORef are IO activities, but newIORef isn't).
I find this point rather slippery. 'newIORef' is a unique-name-provider, but 'unique over what'? When a module is imported twice, should it not create new unique names?
No, it's just binding a name to a value, same as any other binding. The difference is unlike normal top level bindings, that name is not "equal to" any other expression. It just "is", if you get what I mean (I'm sure you do). That's why the proposed syntax borrows the <- from do expressions.
That's not my point. newIORef creates unique names (references). The whole job of newIORef is to create unique names; unique names which "refer to" little tiny bits of state parcelled up somewhere in that mysterious IO monad. It is the scope of this uniqueness I'm talking about: do libraries need these unique names to be unique over each importer, over each thread, over each subprocess: consider a haskell application server or a haskell OS... what is the correct domain of uniqueness?
A large proportion of libraries in fact *can* be written as "reentrant" in this sense, and truly are parameterisable by their state.
I can't help being sceptical about this. AFAICS it doesn't matter how many explicit state handles you tack on to the left of the "-> IO Whatever", the fact that the whole lot ends in "-> IO Whatever" means there's almost certainly some state left unaccounted for and unparameterised (calls the OS are missing an OS state handle for example).
Also, I don't really understand what you mean by "reentrant" in this context. Are you talking about thread safety? (I guess not) Are you implying that APIs of IO libs that mutate Haskell "global" state are some how different from other IO APIs which mutate other "global" state (such as OS state or "world state")? Are they deficient in some way? If so, how can you tell the difference?
'reentrant' is not the right word, although it's a related notion. I was talking about libraries which can safely be initialised more than once, for multiple clients, and they keep around 'separate' state for each client/each time they are initialised. This kind of design is often a precondition for being thread-safe; and it's often plain good design, unless some external 'real world' uniqueness makes it impossible. Jules