
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() { init_runtime_foo(); thunk* tree = hseval("runCont main Exit") while(1) { whnf(tree); switch (tree->tag) { case _Getc: char ch = getchar(); thunk* hch = hs_wrapchar(ch); tree = hsmkapp( tree->payload(0) , hch ); continue; ... case _Exit: return 0; } } } of course, this doesn't refute the non-primitive-ness of IO, but it does refute the uniqueness types part.