{-# LANGUAGE EmptyDataDecls #-} module Time where import Control.Concurrent ( threadDelay ) import qualified Data.Monoid as Mn newtype Time factor a = Time a deriving (Eq, Ord, Show) instance Functor (Time factor) where fmap f (Time a) = Time (f a) instance (Num a) => Mn.Monoid (Time factor a) where mempty = Time 0 mappend (Time x) (Time y) = Time (x+y) sub :: Num a => Time factor a -> Time factor a -> Time factor a sub (Time x) (Time y) = Time (x-y) data One data EM3 a type Milli = EM3 One type Micro = EM3 Milli type Nano = EM3 Micro type Seconds a = Time One a type Milliseconds a = Time Milli a -- unit in Wait constructor type Microseconds a = Time Micro a -- unit of threadDelay type Nanoseconds a = Time Nano a -- unit of ALSA realtime up :: Num a => Time factor a -> Time (EM3 factor) a up (Time a) = Time (1000*a) class Factor factor where seconds :: Num a => a -> Time factor a instance Factor One where seconds = Time instance Factor factor => Factor (EM3 factor) where seconds = up . seconds mul3 :: Time factor a -> Time (EM3 factor) a mul3 (Time t) = Time t milliseconds :: (Factor factor, Num a) => a -> Time (EM3 factor) a milliseconds = mul3 . seconds nanoseconds :: (Factor factor, Num a) => a -> Time (EM3 (EM3 (EM3 factor))) a nanoseconds = mul3 . mul3 . mul3 . seconds pause :: Time Micro Int -> IO () pause (Time t) = threadDelay t -- | we check by the types whether we can format the time value or not class Format factor where formatUnit :: Time factor a -> String instance Format One where formatUnit = const "s" class Format1 factor where formatUnit1 :: Time (EM3 factor) a -> String instance Format1 One where formatUnit1 = const "ms" instance Format1 factor => Format (EM3 factor) where formatUnit = formatUnit1 class Format2 factor where formatUnit2 :: Time (EM3 (EM3 factor)) a -> String instance Format2 One where formatUnit2 = const "us" instance Format2 factor => Format1 (EM3 factor) where formatUnit1 = formatUnit2 class Format3 factor where formatUnit3 :: Time (EM3 (EM3 (EM3 factor))) a -> String instance Format3 One where formatUnit3 = const "ns" instance Format3 factor => Format2 (EM3 factor) where formatUnit2 = formatUnit3 format :: (Format factor, Show a) => Time factor a -> String format time@(Time t) = show t ++ formatUnit time