
Uwe Hollerbach wrote:
lispUTCTime [] = doIOAction (getClockTime) toS allErrs where toS val = String (calendarTimeToString (toUTCTime val))
here you use liftIO (hidden in doIOAction) to use an IO action (getClockTime) inside of a different monad wich contains IO at it's base. so your custom SchemeInterpreterMonad (however it's called) is basically just an extended IO monad.
lispUTCTime [IntNumber n] = return (String (calendarTimeToString (toUTCTime (TOD n 0))))
here you use a pure computation to produce the result string, but then you use return to put it in the monad, too. since IO lives at the base of your custom monad, return will put the String into IO, too. you can't take the IO String out of the IO monad, but you can put the pure String in the IO monad using return.
But after that, it sure seems to me as if I've taken data out of the IO monad... haven't I? Given that the second alternative never entered doIOAction and that after both are done I have a string of characters, prettily formatted to indicate a time, that's what it feels like to this unwashed C programmer.
As explained above, the second alternative uses return instead of doIOAction to "enter" the monad. From a Haskell programmers point of view, you don't have a pure string of characters, but you have a monadic action producing such a string in both cases. That is fine, since your program is inside a REPL anyway, and the very next thing you want to do is to print the computed value, wich is another IO action. but from the point of view of the Scheme programmer using your interpreter, there is no special IO monad around, since the whole Scheme interpreter lives in IO and IO is available to him everywhere. Tillmann