[Haskell-cafe] Top-level state debate on the wiki

John Meacham john at repetae.net
Thu Dec 2 07:18:43 EST 2004

On Thu, Dec 02, 2004 at 10:53:57AM +0000, Keean Schupke wrote:
> Hi John,
>    I am not objecting to the top-level TWIs anymore - since I realised 
> contexts can be
> provided by wrapping the MVar or IORef modules. I just thought the wiki 
> misrepresented
> the calims of your examples (or maybe the claims are a little 
> exaggerated)...

Yeah, I apologize, my comments wern't directed at you in particular, I
was sort of just responding to the whole thread in batch mode.

> >Yes. There are lots of ways to do things without global variables, that
> >was never in doubt. However randomIO is a part of the haskell standard.
> >Why is it not (efficiently) implementable in haskell? There is no
> >particular reason it should not be. it should optimize to exactly about
> >5 instructions to run the linear congruence algorithm on a static
> >location in memory. 
> > 
> >
> The comment was really about the 'introductory' line in the wiki, which 
> seemed
> to me to be stating there are efficiecy reasons for using global 
> variables (false, as
> the examples I gave show) 

That example solves a different problem, I was never claiming that
there wern't efficient ways to solve the unique producer problem in
general, just no efficient way to provide the interface as given in
Data.Unique, a top level declaration of type 'IO Int'.

> (false, as
> I can replace the MVar library and break the unique property - so it is 
> not a static
> guarantee - It just makes it a little more convoluted to get around)... 

If you are allowed to replace code at will then nothing anywhere is
guarenteed in haskell :) I mean you could replace head with 
head = error "No head for you." and a lot of libraries would break. 

It would be the responsibility of anyone replacing key system libraries
to guarentee they are observationally equivalant to what their users
expect. For users of Atom, you still have strong static guarentees at
least as strong as any other guarentees in haskell. So, an
implementation of MVar which randomly cloned state would not break the
static guarentees of Atom as much as it would break the guarentees of
MVar and hence anything that relys on it. 

> As for randomIO
> not being implementable in Haskell, this is true, but it is no more 
> efficient than passing
> a random sequence generator:
>    getRandomSource = do
>       a <- newIORef 0
>       return (nextRandom a)
>       where
>       nextRandom n = do -- where g and f are the generator functions
>          x <- readIORef n
>          writeIORef n (g x)
>          return (f x)

Yes. but that has the same problem as your other example. it is a
different interface than the one we want. If we want to pass around the
state we can use many of the other routines in Random. If we want to
extend the world with the standard generator (which is perfectly
reasonable, and useful enough to make it into the standard haskell
libraries), we are out of luck.

> >Yes, this would be as fast as the global version*, but it implements
> >
> >something else. The entire point of Data.Unique is that one can consider
> >the unique supply as part of the world, just like you consider the
> >filesystem, the screen, the network, various OS routines, etc as part of
> >the world.
> >
> Yes, but not necessarily unique. I may have more than one keyboard... Infact
> any assumption that a resource is unique is normally a bad one - for example
> windows only supporting one display - they probably had to rewrite a lot 
> of code
> using globals when they wanted to support multi-headed machines.

Hrm? This is unrelated, I never claimed anything about uniqueness, just
that the filesystem, screen[s], keyboard[s], etc.. are part of the
world. TWIs are to extending the world in a more efficient way than
writing to a file and a more safe way than using unsafePerformIO. unique
identitfiers are one example of a use of them (assuming you have
appropriate library functions to allow this use).

> > This should be implementable efficiently, after all, you can
> >store the counter in a file in /tmp, or just create a stub C file to do
> >it, so it is obviously not a bad thing to allow, it is already allowed,
> >it just needs to be able to done efficiently or people will resort to
> >unsafe hacks like unsafePerformIO which is a serious impediment to
> >aggressive compiler optimizations and a plauge on the mathematical
> >semantics of the intermediate language.
> > 
> >
> I agree here - I can always change the filesystem with a OS call
> (like chroot) and I can swap the  top-level TWI context with a
> wrapper module around  the MVar/IORef module.

Yeah, I imagine this functionality would be useful to implement
debuggers like 'hat' where you need to collect 'meta-information' about
a run of the program. again, I don't see the ability to replace library
calls like IORef as a weakness in the guarentees provided by stuff that
uses them, as it is up to the replacer of the libraries to do the right

> >No, because then it would not typecheck. the whole point of Atom.hs is
> >
> >that the only way to generate values of type 'Atom' is to go through the
> >single unique hash table.  Hence the static guarentee that there is
> >always an isomorphism between everything of type 'Atom' and everything
> >of type 'String' in the system. This is only made possible by the
> >modules ability to hide access to routines which could be used to break
> >the invarient (such as the raw global hash). This is obviously a very
> >important invarient!
> > 
> >
> But this can be broken with a wrapper module around IORef that
> lets me change contexts... so it is the same in reality, just it
> requires a little more thought to get round the "guarantee".

see above. if you can rewrite libraries then all bets are off. (not that it
isn't sometimes useful to do so). The guarentee is still as strong as
one can hope to achieve in haskell.

> >Let us please not confuse the many philosophical issues against global
> >variables in design which I wholeheartily agree with, with what the
> >global variables proposal is meant to achieve. It is for use at the very
> >lowest level of the libraries. i.e. not to be used by the average
> >person. They are for Atom tables, memoization, anti-memoization, I have
> >desires to move some of the runtime stable/weak pointer infrastructure
> >out of being magic implemented by the runtime, to being implemented in
> >haskell itself, this requires the global hash of stablepointers to be
> >implementable directly. Ghc itself is getting rid of global variables AS
> >SEEN BY THE PROGRAMMER but many libraries still NEED them inside to do 
> >their
> >clever memoization tricks and fast strings which are required to make
> >ghc usable at all. Really, you should not be opposed to them unless you
> >are also opposed to the FFI. At some level, deep inside the libraries,
> >this functionality is needed, just like the FFI. it is even needed to
> >implement the type indexed execution context proposals.
> >
> No as I said, my objection was to the summery line which claimed globals
> necessary for speed or static guarantees - both claims are false (and I
> don't think you claimed as such in the examples - so it is only in regards
> to the wiki entry)

I belive that effectively they are true, because in general, you can't
worry about people rewriting libraries out from under you in
incompatable because then you could never write any correct programs :)

and the efficiency claims were all relative to certain specific APIs.
changing the APIs is another possibility in some cases. Quite an
important one. But it is not universally applicable or desired.
Especially in the cases where you have internal global state but no
implicit observational mutable state. (like in my Atom example) 

> >Exposing the fact there is global state will still be a bad idea, their
> >usage will be hidden by pure interfaces by good programers,
> >
> Of course you cannot stop bad programmers having access to the
> same 'tools' once they are in the language.

True. but as far as these tools go, TWIs are pretty darn safe :) RULES
pragmas let you break pretty much any property of rewriting like
making f . g /= f (g x) without even rewriting the original module!
quite dangerous. and unsafePerformIO lets you break typesafety leading
to a segfault. The worst TWIs allow is bad coding practice :) 
Fortunatly, I don't think Haskell collects many bad programmers. Some
temporarily misguided ones perhaps :)


John Meacham - ⑆repetae.net⑆john⑈ 

More information about the Haskell-Cafe mailing list