[Haskell-cafe] Haskell soltion ofr I/O: is it monads or uniqueness types, after all?

Stefan O'Rear stefanor at cox.net
Sat Feb 10 14:16:19 EST 2007

Gah.  For the first time ever, I seem to have accidentally done a reply to
sender.  (IE Bulat please ignore this message)

On Sat, Feb 10, 2007 at 07:25:19PM +0300, Bulat Ziganshin wrote:
> Hello haskell-cafe,
> just another interesting discussion in russian forum raised such idea:
> we all say that monads are the haskell way to do i/o. is it true? may
> be, uniqueness types, just like in Clean and Mercury, are real way, and
> monads are only the way to write programs that use uniqueness types
> easier?
> so, IO monad is like any other monad - it simplifies writing of
> complex code, but by itself it don't solve any problems. all code that
> can be written with monads can also be written using ordinal function
> calls. we know it for IO monad too - in ghc, we can use low-level
> representation of IO type and write imperative code without use of
> any monad operators

Just because Jhc, GHC, and Yhc (any others? any non-others?) all use
RealWorld# tokens, doesn't mean it's the only way to implement IO.
Note that unsafePerformIO will need to be a primitive...

data Process = Getc (Char -Process)
             | Putc Char (() -Process)
             | forall a. NewIORef a (IORef a -Process)
             | forall a. ReadIORef (IORef a) (a -Process)
             | forall a. WriteIORef (IORef a) a (() -Process)
             | Exit
{- IORef is specifically mentioned because it is the canonical example of something IO can do that 1.2-style streams can't -}

type IO = Cont Process
-- using Cont monad's monad

getChar = Cont $ Getc
putChar = Cont . Putc
newIORef = Cont . NewIORef
readIORef = Cont . ReadIORef
writeIORef a b = Cont $ WriteIORef a b
exit = Cont $ \_ -Exit

{- in runtime, forgive my rusty C -}

int main() {
    thunk* tree = hseval("runCont main Exit")
    while(1) {
	switch (tree->tag) {
	    case _Getc:
	        char ch = getchar();
		thunk* hch = hs_wrapchar(ch);
                tree = hsmkapp( tree->payload(0) , hch );
            case _Exit:
                return 0;

of course, this doesn't refute the non-primitive-ness of IO, but it does refute
the uniqueness types part.

More information about the Haskell-Cafe mailing list