Revision as of 01:30, 13 December 2006 by Claus
Hi, I just stumbled over this IO tutorial, and gave it a quick glance for the usual issues. Unfortunately, it seems to propagate a seriously misleading picture of the IO type: IO cannot, must not be a type synonym. As long as Haskell does not have a uniqueness type system, any functional representation of IO must be hidden behind an abstract type! making only RealWorld abstract is insufficient, as functional programming would still allow us to create RealWorlds out of thin air, or let them disappear: oops :: RealWorld -> (Char,RealWorld) oops rw = let (c1,rw1) = getChar rw (c2,rw2) = getChar rw in ([c2,c1],rw1) whoCares rw = (rw,rw) -- let's make a copy while we're at it fortunately, the fix is simple (but crucial): - make IO a newtype - do handle code inside the abstract type with great care, as many functional equivalences are no longer valid! actually, only the first part is simple, the second part depends on some apparently and happily valid properties of typical optimizations in the implementations. keeping IO abstract also makes it clear that other implementations are possible, and have been used (such as having an interpretation loop for the tree of i/o operations computed by main). also, it might be more useful to think of unsafePerformIO linking into the implicit RealWorld at its point of evaluation, rather than creating an all new one to throw away. this linking in is what makes it so useful as an extension hook for the Haskell implementation.