0

I try to compare the tuple members (date) of an IO tuple with a normal tuple.

d1 ->(Integer, Int, Int) and d2 -> IO (Integer, Int, Int),

Is it possible to compare these two tuples? I've tried something like that:

import Data.Time.Clock
import Data.Time.Calendar
import Data.Time.LocalTime

-- helper functions for tuples
x_fst (x,_,_) = x
x_snd (_,x,_) = x
x_trd (_,_,x) = x

getDate :: IO (Integer, Int, Int)
getDate = do
    now <- getCurrentTime
    tiz <- getCurrentTimeZone
    let zoneNow = utcToLocalTime tiz now
    let date@(year, month, day) = toGeorgian $ localDay zoneNow
    return $ date -- here I will return an IO tuple -> IO (Integer, Int, Int)

compareDates :: a -> IO (Integer, Int, Int) -> IO Bool
compareDates d1 d2 = do
    let year1 = x_fst d1
    let year2 = x_fst d2
    let month1 = x_snd d1
    let month2 = x_snd d2
    let day1 = x_trd d1
    let day2 = x_trd d2
    return $ (year1 == year2 && month1 == month2 && day1 == day2)

But I get the message that I can't compare an IO tuple with a normal tuple:

Couldn't match expected type `(Integer, Integer, Integer)` 
  with actual type `IO (Integer, Int, Int)`
  In the second argument of `compareDates`, namely `date`

Is there a way around it? I would appreciate any help.

Thanks.

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Habebit
  • 957
  • 6
  • 23
  • 1
    Comments are not for extended discussion; this conversation has been [moved to chat](https://chat.stackoverflow.com/rooms/194997/discussion-on-question-by-tabmanrekoj-haskell-how-to-compare-io-tuple-with-norma). – Jean-François Fabre Jun 15 '19 at 17:26

1 Answers1

1

With the help of the comment / chat section I got it to work with the following code:

getDate :: IO Day
getDate = do
    now <- getCurrentTime
    tz <- getCurrentTimeZone
    return . localDay $ utcToLocalTime tz now

main = do
    d2 <- getDate
    return $ fromGregorian 2019 6 15 == d2
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
Habebit
  • 957
  • 6
  • 23
  • 1
    Worth noting that `compareDates` is really just the (automatically generated) `Eq` instance for 3-tuples, so it can be shortened to `compareDates = (==)`. – Silvio Mayolo Jun 15 '19 at 19:54
  • Or less dependent on pre-defined `Eq` instances for tuples, `compareDates (y1, m1, d1) (y2, m2, d2) = y1 == y2 && m1 == m2 && d1 == d2`. – chepner Jun 15 '19 at 20:06
  • There's certainly no need for `do` in `compareDates`; a proper `let` expression would suffice. `let { year1 = xx_fst d2; year2 = xx_fst d2; ... } in year1 == year2 && month1 == month2 && day1 == day2`. – chepner Jun 15 '19 at 20:08
  • 1
    The last line of your `main` should just be `return (compareDates d1 d2)`; there's no need for a second call to `getDate` or `>>=` which shadows the value read by the first call to `getDate`. – chepner Jun 15 '19 at 20:10
  • I have taken the liberty of simplifying your code somewhat. In addition to the improvements already listed in the preceding comments, there's no need to destructure a `Day` into a tuple and compare tuples when `Day`s already have a perfectly suitable comparison available. – Daniel Wagner Jun 16 '19 at 02:23
  • btw, in your original code, `getDate >>= \d2 -> return (compareDates d1 d2)` is equivalent to `do { d2 <- getDate ; return (compareDates d1 d2) }`, so you end up having two exact same lines `d2 <- getDate ; d2 <- getDate ; ...` in your `do` block. so instead of `getDate >>= \d2 -> return (compareDates d1 d2)` it is enough if you just wrote `return (compareDates d1 d2)` (as the comment by chepner is saying, above). another thing is that `do {x <- mx; return f x} == fmap f mx` so you could've also written `main = fmap ((2019,6,15) ==) getDate` (using `==`, as Silvio's comment is saying). – Will Ness Jun 16 '19 at 09:58