
Am Donnerstag, 1. Januar 2009 04:18 schrieb Steve Klabnik:
Hello everyone. I have a quick question about Time.
I was talking about Haskell on the Arch Linux forums today, and someone was trying to put together code that would print a series of periods for, say, 5 minutes. I felt like using 'until' would be the most correct way of going about it, but when I tried to do it...
import Time
makeLater :: ClockTime -> ClockTime makeLater t = addToClockTime (TimeDiff 0 0 0 0 0 5 0) t
updateTime :: ClockTime -> ClockTime updateTime t = t
main = do start <- getClockTime until ((==) $ makeLater start) (updateTime) start putStrLn "done"
Now, updateTime isn't correct. And this wouldn't print any periods. But GHC is giving me errors:
$ runhaskell temp.hs
temp.hs:11:2: Couldn't match expected type `IO t' against inferred type `ClockTime' In the expression: until ((==) $ makeLater start) (updateTime) start In a 'do' expression: until ((==) $ makeLater start) (updateTime) start In the expression: do start <- getClockTime until ((==) $ makeLater start) (updateTime) start putStrLn "done"
I'm not sure where IO t is coming from at all. Am I even on the right track? How would you write this code?
Since it appears as a statement in the main do-block, ghc expects "until ..." to have type IO t. But as Prelude> :t until until :: (a -> Bool) -> (a -> a) -> a -> a until ((==) $ makeLater start) (updateTime) start actually has type ClockTime, so can't appear as a statement in a do-block, that's what ghc tells you. Since you want a timeout, which involves IO, you must do something in IO. You can define a general control structure (I'm sure that is already defined somewhere, but I can't be bothered to hoogle it now) untilM :: (Monad m) => (a -> m Bool) -> (a -> m a) -> a -> m a untilM test action value = do stop <- test value if stop then return value else do newval <- action value untilM test action newval and then isLaterThan :: ClockTime -> IO Bool isLaterThan end = do now <- getClockTime return (end < now) main = do start <- getClockTime let end = addToClockTime (TimeDiff 0 0 0 0 0 5 0) start untilM (\_ -> isLaterThan end) (\_ -> putChar '.') () putStr "\n"