Skip to main content
typo
Source Link
R B
  • 1k
  • 7
  • 9
dbDate :: DatabaseItem -> Maybe UTCTime
dbDate (DbDate utc) = Just etcutc
dbDate _            = Nothing
dbDate :: DatabaseItem -> Maybe UTCTime
dbDate (DbDate utc) = Just etc
dbDate _            = Nothing
dbDate :: DatabaseItem -> Maybe UTCTime
dbDate (DbDate utc) = Just utc
dbDate _            = Nothing
Source Link
R B
  • 1k
  • 7
  • 9

I was wondering if there was anything else that can be done

Well, morally, no. You can either return a nullable value (Maybe UTCTime) or lie (read "1970-01-01 00:00:00 UTC" :: UTCTime) but you can't turn a DbNumber 1 :: DatabaseItem into a UTCTime both unconditionally and truthfully.

The good news is, if you hit on the right set of higher-order functions you don't need to. Maybe values are very easy to work with when you know the extra tools available in Data.Maybe.

Taking as a whole this set of functions related to dates—

filterDbDate :: [DatabaseItem] -> [UTCTime]
filterDbDate [] = []
filterDbDate dataBase = [extractUTCTime item | item <- dataBase, isDbDate item]

isDbDate :: DatabaseItem -> Bool
isDbDate (DbDate _) = True
isDbDate _          = False

extractUTCTime :: DatabaseItem -> UTCTime
extractUTCTime (DbDate utcData) = utcData

mostRecent :: [DatabaseItem] -> UTCTime
mostRecent dataBase = foldr max y ys
                where dates = filterDbDate dataBase
                      y     = head dates
                      ys    = tail dates

We'll begin by throwing out isDbDate and extractUTCTime and writing the DatabaseItem -> Maybe UTCTime function you avoided.

dbDate :: DatabaseItem -> Maybe UTCTime
dbDate (DbDate utc) = Just etc
dbDate _            = Nothing

Now pulling from Data.Maybe, we'll replace filterDbDate with an equivalent code fragment that utilizes mapMaybe.

-- filterDbDate :: [DatabaseItem] -> [UTCTime]
-- filterDbDate db =
     mapMaybe dbDate db

We can use that definition in mostRecent, a function from the standard Prelude, and point free style to achieve a one liner that more than just being clever, emphasizes the power of abstraction in producing concise code that will be instantly comprehensible to other Haskell programmers.

mostRecent :: [DatabaseItem] -> UTCTime
mostRecent = maximum . mapMaybe dbDate

mostRecent still commits the sin of using a partial function though, maximum throws an exception (much like your use of head and tail did before) when the filtered list is empty. Until such time as partial functions are excised from base (and O, do we all lust for and fear such a tumultuous day) you should familiarize yourself with the safe package, which has no dependencies besides base, and provides many alternatives to the partial functions we all know and love.

import Safe.Foldable (maximumMay)

mostRecent :: [DatabaseItem] -> Maybe UTCTime
mostRecent = maximumMay . mapMaybe dbDate