
On Tue, May 31, 2011 at 1:22 AM, George Colpitts
Hi I tried yesod in five minutes and I'm having a problem trying to add a date and time string that would update on refresh. I just want to add it to the simple page you get with yesod in 5 minutes. I can embed a date and time string that is the value of a Haskell variable but that won't refresh on update to the current date and time. My simplistic approach was to put a line in Handler/root.hs:
currTimeAndDate = getClockTime
but that won't compile:
Handler/Root.hs:22:21: No instance for (blaze-html-0.4.1.1:Text.Blaze.ToHtml (IO ClockTime)) arising from a use of `toHtml' Possible fix: add an instance declaration for (blaze-html-0.4.1.1:Text.Blaze.ToHtml (IO ClockTime)) In the second argument of `(.)', namely `toHtml' In the expression: hamlet-0.8.2:Text.Hamlet.Quasi.htmlToHamletMonad . toHtml In a stmt of a 'do' expression: (hamlet-0.8.2:Text.Hamlet.Quasi.htmlToHamletMonad . toHtml) currTimeAndDate
I'm sure it would compile if I wrapped getClockTime with unsafePerformIO to get a String but then refresh of the page wouldn't give me the current time. In addition it doesn't seem like the right way to do this. I'm sure my problem is due to my lack of knowledge of Haskell IO and monads which I do plan to learn thoroughly but right now I'd just like to get this to work. It seems like I could do it with a form in Yesod but that seems like overkill and wouldn't have the look I want. I'm very impressed with the software, the book and the source code for the www.haskellers.com. It is a testimony to the quality of all three that I have got this far, particularly considering how little I know. Any help would be greatly appreciated. Sincerely George
Hi Geroge, Firstly, the answer is to write something like: currTimeAndDate <- liftIO getClockTime You can take that as magic if you like, but I'm guessing from the rest of your email you actually care about understanding things. As you guessed, what's going on here has to do with monads. In particular, getClockTime is not a pure value, but rather an "IO action". In other words, it's an instruction on *how* to produce a value. Another example of this is the code: readFile "myfile.txt". The type of readFile is: readFile :: FilePath -> IO String which basically means "if you give me a file path, I'll give you the instructions on how to generate a string." Once you are inside the IO monad yourself, you can run these instructions, with code like: main = do string <- readFile "myfile.txt" -- notice the <-, not an equal sign putStrLn $ "Here's the file: " ++ string There's a slight extra bit of complication in the code you're trying to run here. The handler code lives in the Handler monad, *not* the IO monad. However, a Handler is a MonadIO, which basically means it can run any IO action. (This is called a monad transformer, but let's not worry about that yet.) The function needed to convert from an IO action to a Handler action is liftIO. I hope that clarifies things a bit. My general recommendation about monads is to not worry too much about that and just keep using the language. Eventually, you'll start to see the inner workings automatically, and you'll suddenly realize that monads are like burritos[1]. But don't try to rush that intuition too much, it just gets frustrating. If you want to study something, what worked for me was trying to understand how the Maybe monad worked, but to each his own. Michael [1] http://byorgey.wordpress.com/2009/01/12/abstraction-intuition-and-the-monad-...