Getting real with Haskell

Yesterday I decided to leave the relative safety of solving exercises in tutorials and instead try solving a small problem I had at work. I had pairs of times (points in time, like Wednesday November 8 01:17) and I needed the difference between them. Not a tricky problem by any stretch of the imagination, but I figured I had to start using Haskell at some point. I might as well make this that point.

I started out by playing around with System.Time and System.Locale in gchi. One thing that seemed missing was a function that took a String and tried to interpret it as a CalendarTime. After a mail to Haskell Cafe I discovered MissingH.

I found myself programming top-down, stubbing “sub functions” while trying to get the types of the current function right. It turns out I was “lucky” and there wasn’t many monads involved, but still I did run into some problems with mixing do notation and let, where, and case. In the end I split out those constructs and kept only the most basic syntactical constructs inside the do.

Here’s the end result, not the most functional piece of Haskell code ever seen, but it’s the first time I dip my toes in the sea of Haskell without a tutorial life-west.

module Main where

import System.Locale
import System.Time
import System.Environment
import MissingH.Time.ParseDate

diffAndToString :: CalendarTime -> CalendarTime -> String
diffAndToString s e = 
    let
        sC = toClockTime s
        eC = toClockTime e
        diff = normalizeTimeDiff $ diffClockTimes eC sC
    in
        formatTimeDiff defaultTimeLocale "%R" diff

calcDiff :: String -> String -> Either String String
calcDiff start end =
    let
        -- I had problems using %Y, so I'm using %C%y instead
        sT = parseCalendarTime defaultTimeLocale "%C%y%m%d-%H%M" start
        eT = parseCalendarTime defaultTimeLocale "%C%y%m%d-%H%M" end
    in
        case (sT, eT) of
        (Nothing, _) -> Left "start time"
        (_, Nothing) -> Left "end time"
        (Just s, Just e) -> Right $ diffAndToString s e

resultString :: String -> String -> String
resultString s e =
    let
        calculatedDiff = calcDiff s e
    in
        case calculatedDiff of
        (Left s) -> "Bad " ++ s
        (Right s) -> s

main :: IO ()
main = do
    args <- getArgs
    putStrLn $ resultString (args !! 0) (args !! 1)
Share

2 Comments

  1. Thanks, dons. I have to say your code is shorter, while still as easy to read as what I wrote (totally subjective comment, of course). Nice!

    I’ve seen maybe in tutorials, but your code had me consulting Hoogle on either.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>