
Hello, haskellers, I have a question for you about the IO monad. On one level, I seem to be "getting" it, at least I seem to be writing code that does what I want, but on another level I am almost certainly not at all clear on some concepts. In various tutorials around the web, I keep finding this notion that the IO monad is "one-way", that you can put stuff into it, but you can't take it out. (And, damn, some of the contortions I went through while trying to figure out how to do exceptions in my little scheme interpreter certainly bear that out! I was sure beating my head against liftIO et al for a fair while...) But let me post some code snippets here:
lispUTCTime [] = doIOAction (getClockTime) toS allErrs where toS val = String (calendarTimeToString (toUTCTime val))
lispUTCTime [IntNumber n] = return (String (calendarTimeToString (toUTCTime (TOD n 0))))
This is a little function I added to the interpreter a couple of days ago: if you enter (UTCtime) with no arguments, it gets the current time and formats it as UTC: like so; this came from the first alternative above: lisp> (UTCtime) "Wed Feb 6 03:57:45 UTC 2008" and if you give an argument, you get that interpreted as a number of seconds since epoch, and that gets formatted as UTC; this is from the second alternative above: lisp> (UTCtime 1.203e9) "Thu Feb 14 14:40:00 UTC 2008" And here's the doIOAction routine: I wrote this, it's not some system-level routine.
doIOAction action ctor epred = do ret <- liftIO (try action) case ret of Left err -> if epred err then throwError (Default (show err)) else return (Bool False) Right val -> return (ctor val)
OK, with all that as background, on one level I understand why I need the doIOAction routine in the first version of lispUTCTime: I'm calling getClockTime, that's an IO action, so I enter the IO monad, get the time, and return: all is cool. In the second version, all I'm doing is taking a number and interpreting it as a time, and writing that in a particular format; again, no problem. 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. So, what's going on there? What's the difference between the two alternatives? I would appreciate any enlightenment you can send my way! regards, Uwe