packages feed

polysemy-time 0.1.3.2 → 0.1.4.0

raw patch · 9 files changed

+182/−32 lines, 9 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Polysemy.Time.At: interpretTimeAt :: forall (diff :: Type) t d r a. TimeUnit diff => Torsor t diff => HasDate t d => Members [Time t d, Embed IO] r => t -> Sem r a -> Sem r a
- Polysemy.Time.At: interpretTimeAtWithStart :: forall diff t d r a. Torsor t diff => TimeUnit diff => HasDate t d => Members [Time t d, Embed IO, State (t, t)] r => Sem r a -> Sem r a
+ Polysemy.Time: [$sel:unDays:Days] :: Days -> Int64
+ Polysemy.Time: [$sel:unHours:Hours] :: Hours -> Int64
+ Polysemy.Time: [$sel:unMicroSeconds:MicroSeconds] :: MicroSeconds -> Int64
+ Polysemy.Time: [$sel:unMilliSeconds:MilliSeconds] :: MilliSeconds -> Int64
+ Polysemy.Time: [$sel:unMinutes:Minutes] :: Minutes -> Int64
+ Polysemy.Time: [$sel:unMonths:Months] :: Months -> Int64
+ Polysemy.Time: [$sel:unNanoSeconds:NanoSeconds] :: NanoSeconds -> Int64
+ Polysemy.Time: [$sel:unSeconds:Seconds] :: Seconds -> Int64
+ Polysemy.Time: [$sel:unWeeks:Weeks] :: Weeks -> Int64
+ Polysemy.Time: [$sel:unYear:Years] :: Years -> Int64
+ Polysemy.Time: interpretTimeGhcConstant :: Member (Embed IO) r => UTCTime -> InterpreterFor GhcTime r
+ Polysemy.Time: interpretTimeGhcConstantNow :: Member (Embed IO) r => InterpreterFor GhcTime r
+ Polysemy.Time: loop :: forall t d u a r. Member (Time t d) r => TimeUnit u => u -> a -> (a -> Sem r a) -> Sem r ()
+ Polysemy.Time: loop_ :: forall t d u r. Member (Time t d) r => TimeUnit u => u -> Sem r () -> Sem r ()
+ Polysemy.Time: while :: forall t d u r. Member (Time t d) r => TimeUnit u => u -> Sem r Bool -> Sem r ()
+ Polysemy.Time.At: interceptTimeAt :: forall (diff :: Type) t d r a. TimeUnit diff => Torsor t diff => HasDate t d => Members [Time t d, Embed IO] r => t -> Sem r a -> Sem r a
+ Polysemy.Time.At: interceptTimeAtWithStart :: forall diff t d r a. Torsor t diff => TimeUnit diff => HasDate t d => Members [Time t d, AtomicState (t, t)] r => Sem r a -> Sem r a
+ Polysemy.Time.At: interceptTimeConstant :: forall t d r a. HasDate t d => Members [Time t d, Embed IO] r => t -> Sem r a -> Sem r a
+ Polysemy.Time.At: interceptTimeConstantNow :: forall t d r a. HasDate t d => Members [Time t d, Embed IO] r => Sem r a -> Sem r a
+ Polysemy.Time.At: interceptTimeConstantState :: forall t d r a. HasDate t d => Members [Time t d, AtomicState t] r => Sem r a -> Sem r a
+ Polysemy.Time.Data.TimeUnit: secondsFrac :: TimeUnit u => u -> Double
+ Polysemy.Time.Ghc: interpretTimeGhcConstant :: Member (Embed IO) r => UTCTime -> InterpreterFor GhcTime r
+ Polysemy.Time.Ghc: interpretTimeGhcConstantNow :: Member (Embed IO) r => InterpreterFor GhcTime r
+ Polysemy.Time.Loop: loop :: forall t d u a r. Member (Time t d) r => TimeUnit u => u -> a -> (a -> Sem r a) -> Sem r ()
+ Polysemy.Time.Loop: loop_ :: forall t d u r. Member (Time t d) r => TimeUnit u => u -> Sem r () -> Sem r ()
+ Polysemy.Time.Loop: while :: forall t d u r. Member (Time t d) r => TimeUnit u => u -> Sem r Bool -> Sem r ()
- Polysemy.Time: adjust :: forall t_axfK d_axfN r_axkK u1_XxfM u2_XxfO. (MemberWithError (Time t_axfK d_axfN) r_axkK, AddTimeUnit t_axfK u1_XxfM u2_XxfO) => u1_XxfM -> Sem r_axkK ()
+ Polysemy.Time: adjust :: forall t_axil d_axio r_axnl u1_Xxin u2_Xxip. (MemberWithError (Time t_axil d_axio) r_axnl, AddTimeUnit t_axil u1_Xxin u2_Xxip) => u1_Xxin -> Sem r_axnl ()
- Polysemy.Time: now :: forall t_axfx d_axfy r_axkE. MemberWithError (Time t_axfx d_axfy) r_axkE => Sem r_axkE t_axfx
+ Polysemy.Time: now :: forall t_axi8 d_axi9 r_axnf. MemberWithError (Time t_axi8 d_axi9) r_axnf => Sem r_axnf t_axi8
- Polysemy.Time: setDate :: forall t_axfQ d_axfP r_axkM. MemberWithError (Time t_axfQ d_axfP) r_axkM => d_axfP -> Sem r_axkM ()
+ Polysemy.Time: setDate :: forall t_axir d_axiq r_axnn. MemberWithError (Time t_axir d_axiq) r_axnn => d_axiq -> Sem r_axnn ()
- Polysemy.Time: setTime :: forall t_axfH d_axfI r_axkI. MemberWithError (Time t_axfH d_axfI) r_axkI => t_axfH -> Sem r_axkI ()
+ Polysemy.Time: setTime :: forall t_axii d_axij r_axnj. MemberWithError (Time t_axii d_axij) r_axnj => t_axii -> Sem r_axnj ()
- Polysemy.Time: sleep :: forall t_axfE d_axfF r_axkG u_XxfE. (MemberWithError (Time t_axfE d_axfF) r_axkG, TimeUnit u_XxfE) => u_XxfE -> Sem r_axkG ()
+ Polysemy.Time: sleep :: forall t_axif d_axig r_axnh u_Xxif. (MemberWithError (Time t_axif d_axig) r_axnh, TimeUnit u_Xxif) => u_Xxif -> Sem r_axnh ()
- Polysemy.Time: today :: forall t_axfA d_axfB r_axkF. MemberWithError (Time t_axfA d_axfB) r_axkF => Sem r_axkF d_axfB
+ Polysemy.Time: today :: forall t_axib d_axic r_axng. MemberWithError (Time t_axib d_axic) r_axng => Sem r_axng d_axic
- Polysemy.Time.At: dateCurrentRelative :: forall diff t d r. Torsor t diff => Members [Time t d, Embed IO, State (t, t)] r => Sem r t
+ Polysemy.Time.At: dateCurrentRelative :: forall diff t d r. Torsor t diff => Members [Time t d, AtomicState (t, t)] r => Sem r t
- Polysemy.Time.Data.Time: adjust :: forall t_axfK d_axfN r_axkK u1_XxfM u2_XxfO. (MemberWithError (Time t_axfK d_axfN) r_axkK, AddTimeUnit t_axfK u1_XxfM u2_XxfO) => u1_XxfM -> Sem r_axkK ()
+ Polysemy.Time.Data.Time: adjust :: forall t_axil d_axio r_axnl u1_Xxin u2_Xxip. (MemberWithError (Time t_axil d_axio) r_axnl, AddTimeUnit t_axil u1_Xxin u2_Xxip) => u1_Xxin -> Sem r_axnl ()
- Polysemy.Time.Data.Time: now :: forall t_axfx d_axfy r_axkE. MemberWithError (Time t_axfx d_axfy) r_axkE => Sem r_axkE t_axfx
+ Polysemy.Time.Data.Time: now :: forall t_axi8 d_axi9 r_axnf. MemberWithError (Time t_axi8 d_axi9) r_axnf => Sem r_axnf t_axi8
- Polysemy.Time.Data.Time: setDate :: forall t_axfQ d_axfP r_axkM. MemberWithError (Time t_axfQ d_axfP) r_axkM => d_axfP -> Sem r_axkM ()
+ Polysemy.Time.Data.Time: setDate :: forall t_axir d_axiq r_axnn. MemberWithError (Time t_axir d_axiq) r_axnn => d_axiq -> Sem r_axnn ()
- Polysemy.Time.Data.Time: setTime :: forall t_axfH d_axfI r_axkI. MemberWithError (Time t_axfH d_axfI) r_axkI => t_axfH -> Sem r_axkI ()
+ Polysemy.Time.Data.Time: setTime :: forall t_axii d_axij r_axnj. MemberWithError (Time t_axii d_axij) r_axnj => t_axii -> Sem r_axnj ()
- Polysemy.Time.Data.Time: sleep :: forall t_axfE d_axfF r_axkG u_XxfE. (MemberWithError (Time t_axfE d_axfF) r_axkG, TimeUnit u_XxfE) => u_XxfE -> Sem r_axkG ()
+ Polysemy.Time.Data.Time: sleep :: forall t_axif d_axig r_axnh u_Xxif. (MemberWithError (Time t_axif d_axig) r_axnh, TimeUnit u_Xxif) => u_Xxif -> Sem r_axnh ()
- Polysemy.Time.Data.Time: today :: forall t_axfA d_axfB r_axkF. MemberWithError (Time t_axfA d_axfB) r_axkF => Sem r_axkF d_axfB
+ Polysemy.Time.Data.Time: today :: forall t_axib d_axic r_axng. MemberWithError (Time t_axib d_axic) r_axng => Sem r_axng d_axic

Files

changelog.md view
@@ -1,3 +1,10 @@+# Unreleased++# 0.1.4.0+* Add `secondsFrac`, a combinator that converts a unit into a fractional number of seconds.+* Add combinators for repeatedly running an action with a sleep interval+* Add interpreters that remain at a fixed instant+ # 0.1.3.0 * Added `measure`, a combinator that returns the time span an action takes. 
lib/Polysemy/Time.hs view
@@ -10,11 +10,16 @@   -- * Interpreters   interpretTimeGhc,   interpretTimeGhcAt,+  interpretTimeGhcConstant,+  interpretTimeGhcConstantNow,   -- * Data types   module Polysemy.Time.Data.TimeUnit,   module Polysemy.Time.Calendar,   -- * Combinators   measure,+  while,+  loop,+  loop_, ) where  import Polysemy.Time.Calendar (@@ -29,20 +34,27 @@   ) import Polysemy.Time.Data.Time (Time (..), adjust, now, setDate, setTime, sleep, today) import Polysemy.Time.Data.TimeUnit (-  Days (Days),-  Hours (Hours),-  MicroSeconds (MicroSeconds),-  MilliSeconds (MilliSeconds),-  Minutes (Minutes),-  Months (Months),-  NanoSeconds (NanoSeconds),-  Seconds (Seconds),+  Days (..),+  Hours (..),+  MicroSeconds (..),+  MilliSeconds (..),+  Minutes (..),+  Months (..),+  NanoSeconds (..),+  Seconds (..),   TimeUnit,-  Weeks (Weeks),-  Years (Years),+  Weeks (..),+  Years (..),   convert,   )-import Polysemy.Time.Ghc (GhcTime, interpretTimeGhc, interpretTimeGhcAt)+import Polysemy.Time.Ghc (+  GhcTime,+  interpretTimeGhc,+  interpretTimeGhcAt,+  interpretTimeGhcConstant,+  interpretTimeGhcConstantNow,+  )+import Polysemy.Time.Loop (loop, loop_, while) import Polysemy.Time.Measure (measure) import Polysemy.Time.Orphans () 
lib/Polysemy/Time/At.hs view
@@ -1,7 +1,7 @@ module Polysemy.Time.At where  import Polysemy (intercept)-import Torsor (Torsor(add), difference)+import Torsor (Torsor (add), difference)  import Polysemy.Time.Calendar (HasDate, date, dateToTime) import qualified Polysemy.Time.Data.Time as Time@@ -13,24 +13,24 @@ dateCurrentRelative ::   ∀ diff t d r .   Torsor t diff =>-  Members [Time t d, Embed IO, State (t, t)] r =>+  Members [Time t d, AtomicState (t, t)] r =>   Sem r t dateCurrentRelative = do-  (startAt, startActual) <- get @(t, t)+  (startAt, startActual) <- atomicGet @(t, t)   (`add` startAt) . (`difference` startActual) <$> Time.now @t @d  -- |Given real and adjusted start time, change all calls to 'Time.Now' and 'Time.Today' to be relative to that start -- time. -- This needs to be interpreted with a vanilla interpreter for 'Time' once more.-interpretTimeAtWithStart ::+interceptTimeAtWithStart ::   ∀ diff t d r a .   Torsor t diff =>   TimeUnit diff =>   HasDate t d =>-  Members [Time t d, Embed IO, State (t, t)] r =>+  Members [Time t d, AtomicState (t, t)] r =>   Sem r a ->   Sem r a-interpretTimeAtWithStart =+interceptTimeAtWithStart =   intercept @(Time t d) \case     Time.Now ->       dateCurrentRelative @diff @t @d@@ -40,16 +40,16 @@       Time.sleep @t @d t     Time.SetTime startAt -> do       startActual <- Time.now @t @d-      put @(t, t) (startAt, startActual)+      atomicPut @(t, t) (startAt, startActual)     Time.Adjust diff -> do-      modify' @(t, t) \ (old, actual) -> (addTimeUnit diff old, actual)+      atomicModify' @(t, t) \ (old, actual) -> (addTimeUnit diff old, actual)     Time.SetDate startAt -> do       startActual <- Time.now @t @d-      put @(t, t) (dateToTime startAt, startActual)-{-# INLINE interpretTimeAtWithStart #-}+      atomicPut @(t, t) (dateToTime startAt, startActual)+{-# inline interceptTimeAtWithStart #-}  -- |Interpret 'Time' so that the time when the program starts is @startAt@.-interpretTimeAt ::+interceptTimeAt ::   ∀ (diff :: Type) t d r a .   TimeUnit diff =>   Torsor t diff =>@@ -58,7 +58,62 @@   t ->   Sem r a ->   Sem r a-interpretTimeAt startAt sem = do+interceptTimeAt startAt sem = do   startActual <- Time.now @t @d-  evalState (startAt, startActual) . interpretTimeAtWithStart @diff @t @d . raise $ sem-{-# INLINE interpretTimeAt #-}+  tv <- newTVarIO (startAt, startActual)+  runAtomicStateTVar tv . interceptTimeAtWithStart @diff @t @d . raise $ sem+{-# inline interceptTimeAt #-}++-- |Change all calls to 'Time.Now' and 'Time.Today' to return the given start time.+-- This needs to be interpreted with a vanilla interpreter for 'Time' once more.+interceptTimeConstantState ::+  ∀ t d r a .+  HasDate t d =>+  Members [Time t d, AtomicState t] r =>+  Sem r a ->+  Sem r a+interceptTimeConstantState =+  intercept @(Time t d) \case+    Time.Now ->+      atomicGet+    Time.Today ->+      atomicGets @t date+    Time.Sleep t ->+      Time.sleep @t @d t+    Time.SetTime now ->+      atomicPut now+    Time.Adjust diff ->+      atomicModify' @t (addTimeUnit diff)+    Time.SetDate startAt ->+      atomicPut @t (dateToTime startAt)+{-# inline interceptTimeConstantState #-}++-- |Interpret 'Time' so that the time is always @startAt@.+--+-- The time can still be changed with 'Time.setTime', 'Time.adjust' and 'Time.setDate'.+interceptTimeConstant ::+  ∀ t d r a .+  HasDate t d =>+  Members [Time t d, Embed IO] r =>+  t ->+  Sem r a ->+  Sem r a+interceptTimeConstant startAt sem = do+  tv <- newTVarIO startAt+  runAtomicStateTVar tv . interceptTimeConstantState @t . raise $ sem+{-# inline interceptTimeConstant #-}++-- |Interpret 'Time' so that the time is always the time at the start of interpretation.+--+-- The time can still be changed with 'Time.setTime', 'Time.adjust' and 'Time.setDate'.+interceptTimeConstantNow ::+  ∀ t d r a .+  HasDate t d =>+  Members [Time t d, Embed IO] r =>+  Sem r a ->+  Sem r a+interceptTimeConstantNow sem = do+  now <- Time.now @t @d+  tv <- newTVarIO now+  runAtomicStateTVar tv . interceptTimeConstantState @t . raise $ sem+{-# inline interceptTimeConstantNow #-}
lib/Polysemy/Time/Data/TimeUnit.hs view
@@ -172,6 +172,14 @@ addTimeUnit =   add . convert +-- |Convert a unit into a number of seconds, keeping the subsecond part as fractional digits.+secondsFrac ::+  TimeUnit u =>+  u ->+  Double+secondsFrac u =+  fromIntegral (unNanoSeconds (convert u)) / 1e9+ defaultJson ''Years defaultJson ''Months defaultJson ''Weeks
lib/Polysemy/Time/Debug.hs view
@@ -79,7 +79,7 @@   a tr msg a =   unsafePerformIO (a <$ debugPrint (srcLoc callStack) msg)-{-# INLINE tr #-}+{-# inline tr #-}  trs ::   Show a =>@@ -88,7 +88,7 @@   a trs a =   unsafePerformIO (a <$ debugPrint (srcLoc callStack) (show a))-{-# INLINE trs #-}+{-# inline trs #-}  trs' ::   Show b =>@@ -98,4 +98,4 @@   a trs' b a =   unsafePerformIO (a <$ debugPrint (srcLoc callStack) (show b))-{-# INLINE trs' #-}+{-# inline trs' #-}
lib/Polysemy/Time/Ghc.hs view
@@ -4,7 +4,7 @@ import Data.Time (Day, NominalDiffTime, UTCTime, utctDay) import Data.Time.Clock.System (getSystemTime, systemToUTCTime) -import Polysemy.Time.At (interpretTimeAt)+import Polysemy.Time.At (interceptTimeAt, interceptTimeConstant, interceptTimeConstantNow) import qualified Polysemy.Time.Data.Time as Time import Polysemy.Time.Data.Time (Time) import Polysemy.Time.Data.TimeUnit (MicroSeconds (MicroSeconds), convert)@@ -45,4 +45,20 @@   UTCTime ->   InterpreterFor GhcTime r interpretTimeGhcAt t =-  interpretTimeGhc . interpretTimeAt @NominalDiffTime t+  interpretTimeGhc . interceptTimeAt @NominalDiffTime t++-- |Interpret 'Time' with the types from 'Data.Time', customizing the current time to be constant.+interpretTimeGhcConstant ::+  Member (Embed IO) r =>+  UTCTime ->+  InterpreterFor GhcTime r+interpretTimeGhcConstant t =+  interpretTimeGhc . interceptTimeConstant t++-- |Interpret 'Time' with the types from 'Data.Time', customizing the current time to be constantly the time at the+-- start of interpretation.+interpretTimeGhcConstantNow ::+  Member (Embed IO) r =>+  InterpreterFor GhcTime r+interpretTimeGhcConstantNow =+  interpretTimeGhc . interceptTimeConstantNow @UTCTime
+ lib/Polysemy/Time/Loop.hs view
@@ -0,0 +1,49 @@+module Polysemy.Time.Loop where++import Polysemy.Time.Data.Time (Time)+import Polysemy.Time.Data.TimeUnit (TimeUnit)+import qualified Polysemy.Time.Data.Time as Time++-- |Repeatedly run the @action@, sleeping for @interval@ between executions.+-- Stops when @action@ returns @False@.+while ::+  ∀ t d u r .+  Member (Time t d) r =>+  TimeUnit u =>+  u ->+  Sem r Bool ->+  Sem r ()+while interval action =+  spin+  where+    spin =+      whenM action (Time.sleep @t @d interval *> spin)++-- |Repeatedly run the @action@, sleeping for @interval@ between executions.+-- The result of @action@ is passed back to it for the next run, starting with @initial@.+loop ::+  ∀ t d u a r .+  Member (Time t d) r =>+  TimeUnit u =>+  u ->+  a ->+  (a -> Sem r a) ->+  Sem r ()+loop interval initial action =+  forever (spin initial)+  where+    spin a = do+      new <- action a+      Time.sleep @t @d interval+      spin new++-- |Repeatedly run the @action@, sleeping for @interval@ between executions.+loop_ ::+  ∀ t d u r .+  Member (Time t d) r =>+  TimeUnit u =>+  u ->+  Sem r () ->+  Sem r ()+loop_ interval action =+  forever (action *> Time.sleep @t @d interval)
polysemy-time.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           polysemy-time-version:        0.1.3.2+version:        0.1.4.0 synopsis:       Polysemy Effect for Time description:    Please see the readme on Github at <https://github.com/tek/polysemy-time> category:       Time@@ -30,6 +30,7 @@       Polysemy.Time.Debug       Polysemy.Time.Diff       Polysemy.Time.Ghc+      Polysemy.Time.Loop       Polysemy.Time.Measure       Polysemy.Time.Orphans       Polysemy.Time.Prelude
test/Polysemy/Time/Test/TimeUnitTest.hs view
@@ -2,7 +2,7 @@  import Polysemy.Test (UnitTest, assertEq, runTestAuto) -import Polysemy.Time.Data.TimeUnit (MicroSeconds (MicroSeconds), MilliSeconds (MilliSeconds))+import Polysemy.Time.Data.TimeUnit (MicroSeconds (MicroSeconds), MilliSeconds (MilliSeconds), secondsFrac)  test_fractional :: UnitTest test_fractional =@@ -10,3 +10,5 @@     assertEq @_ @IO (MilliSeconds 50) 0.05     assertEq @_ @IO (MicroSeconds 200) 0.0002     assertEq @_ @IO (MilliSeconds 50) (MilliSeconds 100 / MilliSeconds 2)+    assertEq @_ @IO (MilliSeconds 50) (MilliSeconds 100 / 2)+    assertEq @_ @IO 0.05 (secondsFrac (MilliSeconds 50))