packages feed

time-domain-0.1.0.0: src/Data/TimeDomain.hs

{- |
This module defines the 'TimeDomain' class.
Its instances model time,
simulated and realtime.
Several instances such as 'UTCTime', 'Double' and 'Integer' are supplied here.
-}

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeFamilies #-}

module Data.TimeDomain
  ( module Data.TimeDomain
  , UTCTime
  )
  where

-- time
import Data.Time.Clock (UTCTime, diffUTCTime)

{- |
A time domain is an affine space representing a notion of time,
such as real time, simulated time, steps, or a completely different notion.

Expected law:

@(t1 `diffTime` t3) `difference` (t1 `diffTime` t2) = t2 `diffTime` t3@
-}
class TimeDifference (Diff time) => TimeDomain time where
  -- | The type of differences or durations between two timestamps
  type Diff time

  {- | Compute the difference between two timestamps.

  Mnemonic: 'diffTime' behaves like the '(-)' operator:

  @'diffTime' earlier later = later `'diffTime'` earlier@ is the duration it takes from @earlier@ to @later.
  -}
  diffTime :: time -> time -> Diff time

{- | A type of durations, or differences betweens time stamps.

For the expected law, see 'TimeDomain'.
-}
class TimeDifference d where
  -- | Calculate the difference between two durations,
  --   compatibly with 'diffTime'.
  difference :: d -> d -> d

-- | Differences between 'UTCTime's are measured in seconds.
instance TimeDomain UTCTime where
  type Diff UTCTime = Double
  diffTime t1 t2 = realToFrac $ diffUTCTime t1 t2

instance TimeDifference Double where
  difference = (-)

instance TimeDomain Double where
  type Diff Double = Double
  diffTime = (-)

instance TimeDifference Float where
  difference = (-)

instance TimeDomain Float where
  type Diff Float = Float
  diffTime = (-)

instance TimeDifference Integer where
  difference = (-)

instance TimeDomain Integer where
  type Diff Integer = Integer
  diffTime = (-)

instance TimeDifference () where
  difference _ _ = ()

instance TimeDomain () where
  type Diff () = ()
  diffTime _ _ = ()

-- | Any 'Num' can be wrapped to form a 'TimeDomain'.
newtype NumTimeDomain a = NumTimeDomain { fromNumTimeDomain :: a }
  deriving Num

instance Num a => TimeDifference (NumTimeDomain a) where
  difference = (-)

instance Num a => TimeDomain (NumTimeDomain a) where
  type Diff (NumTimeDomain a) = NumTimeDomain a
  diffTime = (-)