From 593e364c8a04a8c5024492ef49d6fb4029cf5dce Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Mon, 3 Apr 2017 17:31:29 +0400 Subject: [PATCH 01/33] WIP: Add Interval --- src/Data/Interval/Interval.purs | 42 +++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/Data/Interval/Interval.purs diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs new file mode 100644 index 0000000..c7944b2 --- /dev/null +++ b/src/Data/Interval/Interval.purs @@ -0,0 +1,42 @@ +module Data.Interval + ( Duration + , Interval + , RecurringInterval + ) where + +import Prelude + +import Data.Date as Date +import Data.Inteval.Duration as Duration +import Data.Time as Time + +data Interval a + = StartEnd a a + | StartDuration Duration a + | DurationEnd a Duration + | JustDuration Duration + +data RecurringInterval a = RecurringInterval (Maybe Int) (Interval a) +data Duration + = DurationWeek Week + | DurationDateTime + { year :: Year + , month :: Month + , day :: Day + , week :: Week + , day :: Day + , hours :: Hours + , minutes :: Minutes + , seconds :: Seconds + , milliseconds :: Milliseconds + } + +data Year = Int +data Month = Int +data Day = Int +data Week = Int +data Day = Int +data Hours = Int +data Minutes = Int +data Seconds = Int +data Milliseconds = Int From 37b6f364c3d138c2cc8fb3a2e28b79cf8c9849c9 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Mon, 3 Apr 2017 17:39:28 +0400 Subject: [PATCH 02/33] remove unused imports --- src/Data/Interval/Interval.purs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index c7944b2..da76bb4 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -6,10 +6,6 @@ module Data.Interval import Prelude -import Data.Date as Date -import Data.Inteval.Duration as Duration -import Data.Time as Time - data Interval a = StartEnd a a | StartDuration Duration a From fac9d4b4455211f842248007fdc3477fdc383d00 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Mon, 3 Apr 2017 20:48:46 +0400 Subject: [PATCH 03/33] remove dublicats --- src/Data/Interval/Interval.purs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index da76bb4..0065e44 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -19,8 +19,6 @@ data Duration { year :: Year , month :: Month , day :: Day - , week :: Week - , day :: Day , hours :: Hours , minutes :: Minutes , seconds :: Seconds @@ -31,7 +29,6 @@ data Year = Int data Month = Int data Day = Int data Week = Int -data Day = Int data Hours = Int data Minutes = Int data Seconds = Int From 0805ce406ff3d05ef8143fe23d18982157176253 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 4 Apr 2017 17:28:48 +0400 Subject: [PATCH 04/33] update Duration --- src/Data/Interval/Interval.purs | 114 ++++++++++++++++++++++++++------ test/Test/Main.purs | 14 +++- 2 files changed, 106 insertions(+), 22 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 0065e44..a909a3a 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -2,9 +2,27 @@ module Data.Interval ( Duration , Interval , RecurringInterval + , year + , month + , week + , day + , hours + , minutes + , seconds + , milliseconds + , mkDuration + , DurationView ) where import Prelude +import Data.Monoid (class Monoid, mempty) + +import Data.Maybe (Maybe) +import Data.List (List(..), (:), filter) +import Data.Tuple (Tuple(..)) + + +data RecurringInterval a = RecurringInterval (Maybe Int) (Interval a) data Interval a = StartEnd a a @@ -12,24 +30,78 @@ data Interval a | DurationEnd a Duration | JustDuration Duration -data RecurringInterval a = RecurringInterval (Maybe Int) (Interval a) -data Duration - = DurationWeek Week - | DurationDateTime - { year :: Year - , month :: Month - , day :: Day - , hours :: Hours - , minutes :: Minutes - , seconds :: Seconds - , milliseconds :: Milliseconds - } - -data Year = Int -data Month = Int -data Day = Int -data Week = Int -data Hours = Int -data Minutes = Int -data Seconds = Int -data Milliseconds = Int +type DurationView = + { year ∷ Number + , month ∷ Number + , day ∷ Number + , hours ∷ Number + , minutes ∷ Number + , seconds ∷ Number + , milliseconds ∷ Number + } + +mkDuration ∷ DurationView → Duration +mkDuration d = Duration $ + ( Tuple Year d.year + : Tuple Month d.month + : Tuple Day d.day + : Tuple Hours d.hours + : Tuple Minutes d.minutes + : Tuple Seconds d.seconds + : Tuple Milliseconds d.milliseconds + : Nil + ) # filter (\(Tuple _ v) → v /= 0.0) + +data Duration = Duration DurationIn +type DurationIn = List (Tuple DurationComponent Number) + +-- TODO maybe we should implement custom Eq and Ord +derive instance eqDuration ∷ Eq Duration + +data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds | Milliseconds +derive instance eqDurationComponent ∷ Eq DurationComponent +derive instance ordDurationComponent ∷ Ord DurationComponent + +appendComponents ∷ DurationIn → DurationIn → DurationIn +appendComponents Nil x = x +appendComponents x Nil = x +appendComponents ass@(a@(Tuple aC aV) : as) bss@(b@(Tuple bC bV) : bs) = + if aC == bC then Tuple aC (aV + bV) : appendComponents as bs + else if aC > bC then a : appendComponents as bss + else b : appendComponents ass bs + +-- appendComponents ass@(a:as) bss@(b:bs) = case a, b of +-- Tuple xC xV, Tuple yC yV | xC == yC → Tuple xC (xV + yV) : appendComponents as bs +-- Tuple xC xV, Tuple yC yV | xC > yC → a : appendComponents as bss +-- Tuple xC xV, Tuple yC yV | xC < yC → b : appendComponents ass bs + +instance semigroupDuration ∷ Semigroup Duration where + append (Duration a) (Duration b) = Duration (appendComponents a b) + +instance monoidDuration ∷ Monoid Duration where + mempty = Duration mempty + + +week ∷ Number → Duration +week = Duration <<< pure <<< Tuple Day <<< (_ * 7.0) + +year ∷ Number → Duration +year = Duration <<< pure <<< Tuple Year + +month ∷ Number → Duration +month = Duration <<< pure <<< Tuple Month + +day ∷ Number → Duration +day = Duration <<< pure <<< Tuple Day + +hours ∷ Number → Duration +hours = Duration <<< pure <<< Tuple Hours + +minutes ∷ Number → Duration +minutes = Duration <<< pure <<< Tuple Minutes + +seconds ∷ Number → Duration +seconds = Duration <<< pure <<< Tuple Seconds + +milliseconds ∷ Number → Duration +milliseconds = Duration <<< pure <<< Tuple Milliseconds diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 1d55817..019c530 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -9,11 +9,13 @@ import Data.Enum (class BoundedEnum, Cardinality, toEnum, enumFromTo, cardinalit import Data.Date as Date import Data.Time as Time import Data.Time.Duration as Duration +import Data.Interval as Interval import Data.Array as Array import Data.DateTime as DateTime import Data.DateTime.Instant as Instant import Data.Maybe (Maybe(..), fromJust) import Data.Tuple (Tuple(..), snd) +import Data.Monoid (mempty) import Data.Newtype (unwrap) import Type.Proxy (Proxy(..)) @@ -24,7 +26,17 @@ type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit main :: Tests main = do - + log "check Duration monoid" + let id1 = Interval.mkDuration $ + { year: 1.0 + , month: 0.0 + , day: 0.0 + , hours: 0.0 + , minutes: 0.0 + , seconds: 0.0 + , milliseconds: 0.0 + } + assert $ id1 == (mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0)) -- time -------------------------------------------------------------------- log "Check that Hour is a good BoundedEnum" From 5c49ea68ce8482d2fc81d9342ec39403bdb114ef Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 4 Apr 2017 19:57:24 +0400 Subject: [PATCH 05/33] add couple instances for Duration and Interval --- src/Data/Interval/Interval.purs | 77 ++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 16 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index a909a3a..d41e742 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -1,7 +1,9 @@ module Data.Interval ( Duration - , Interval - , RecurringInterval + , Interval(..) + , RecurringInterval(..) + , DurationView + , mkDuration , year , month , week @@ -10,12 +12,14 @@ module Data.Interval , minutes , seconds , milliseconds - , mkDuration - , DurationView ) where import Prelude + +import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL) +import Data.Traversable (class Traversable, sequenceDefault) import Data.Monoid (class Monoid, mempty) +import Control.Extend (class Extend) import Data.Maybe (Maybe) import Data.List (List(..), (:), filter) @@ -26,10 +30,43 @@ data RecurringInterval a = RecurringInterval (Maybe Int) (Interval a) data Interval a = StartEnd a a - | StartDuration Duration a - | DurationEnd a Duration + | DurationEnd Duration a + | StartDuration a Duration | JustDuration Duration +instance showInterval ∷ (Show a) => Show (Interval a) where + show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" + show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" + show (StartDuration x d) = "(StartDuration " <> show x <> " " <> show d <> ")" + show (JustDuration d) = "(JustDuration " <> show d <> ")" + +instance functorInterval ∷ Functor Interval where + map f (StartEnd x y) = StartEnd (f x) (f y ) + map f (DurationEnd d x) = DurationEnd d (f x ) + map f (StartDuration x d) = StartDuration (f x) d + map _ (JustDuration d) = JustDuration d + +instance foldableInterval ∷ Foldable Interval where + foldl f z (StartEnd x y) = (z `f` x) `f` y + foldl f z (DurationEnd d x) = z `f` x + foldl f z (StartDuration x d) = z `f` x + foldl _ z _ = z + foldr x = foldrDefault x + foldMap = foldMapDefaultL + +instance traversableInterval ∷ Traversable Interval where + traverse f (StartEnd x y) = StartEnd <$> f x <*> f y + traverse f (DurationEnd d x) = f x <#> DurationEnd d + traverse f (StartDuration x d) = f x <#> (_ `StartDuration` d) + traverse _ (JustDuration d) = pure (JustDuration d) + sequence = sequenceDefault + +instance extendInterval ∷ Extend Interval where + extend f a@(StartEnd x y) = StartEnd (f a) (f a ) + extend f a@(DurationEnd d x) = DurationEnd d (f a ) + extend f a@(StartDuration x d) = StartDuration (f a) d + extend f (JustDuration d) = JustDuration d + type DurationView = { year ∷ Number , month ∷ Number @@ -55,25 +92,33 @@ mkDuration d = Duration $ data Duration = Duration DurationIn type DurationIn = List (Tuple DurationComponent Number) --- TODO maybe we should implement custom Eq and Ord derive instance eqDuration ∷ Eq Duration +instance showDuration ∷ Show Duration where + show (Duration d)= "(Duration " <> show d <> ")" + data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds | Milliseconds + +instance showDurationComponent ∷ Show DurationComponent where + show Year = "Year" + show Month = "Month" + show Day = "Day" + show Hours = "Hours" + show Minutes = "Minutes" + show Seconds = "Seconds" + show Milliseconds= "Millisecond" + derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent appendComponents ∷ DurationIn → DurationIn → DurationIn appendComponents Nil x = x appendComponents x Nil = x -appendComponents ass@(a@(Tuple aC aV) : as) bss@(b@(Tuple bC bV) : bs) = - if aC == bC then Tuple aC (aV + bV) : appendComponents as bs - else if aC > bC then a : appendComponents as bss - else b : appendComponents ass bs - --- appendComponents ass@(a:as) bss@(b:bs) = case a, b of --- Tuple xC xV, Tuple yC yV | xC == yC → Tuple xC (xV + yV) : appendComponents as bs --- Tuple xC xV, Tuple yC yV | xC > yC → a : appendComponents as bss --- Tuple xC xV, Tuple yC yV | xC < yC → b : appendComponents ass bs +appendComponents ass@(a:as) bss@(b:bs) = case a, b of + Tuple aC aV, Tuple bC bV + | aC > bC → a : appendComponents as bss + | aC < bC → b : appendComponents ass bs + | otherwise → Tuple aC (aV + bV) : appendComponents as bs instance semigroupDuration ∷ Semigroup Duration where append (Duration a) (Duration b) = Duration (appendComponents a b) From d7dec5aa4bc36966feddd3dcb9f3010d5849f16e Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 4 Apr 2017 20:08:55 +0400 Subject: [PATCH 06/33] reorder code --- src/Data/Interval/Interval.purs | 48 ++++++++++++++++----------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index d41e742..e0b27b2 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -67,6 +67,30 @@ instance extendInterval ∷ Extend Interval where extend f a@(StartDuration x d) = StartDuration (f a) d extend f (JustDuration d) = JustDuration d +data Duration = Duration DurationIn +type DurationIn = List (Tuple DurationComponent Number) + +-- TODO `day 1 == hours 24` +derive instance eqDuration ∷ Eq Duration +instance showDuration ∷ Show Duration where + show (Duration d)= "(Duration " <> show d <> ")" + +instance semigroupDuration ∷ Semigroup Duration where + append (Duration a) (Duration b) = Duration (appendComponents a b) + +instance monoidDuration ∷ Monoid Duration where + mempty = Duration mempty + +appendComponents ∷ DurationIn → DurationIn → DurationIn +appendComponents Nil x = x +appendComponents x Nil = x +appendComponents ass@(a:as) bss@(b:bs) = case a, b of + Tuple aC aV, Tuple bC bV + | aC > bC → a : appendComponents as bss + | aC < bC → b : appendComponents ass bs + | otherwise → Tuple aC (aV + bV) : appendComponents as bs + + type DurationView = { year ∷ Number , month ∷ Number @@ -89,14 +113,6 @@ mkDuration d = Duration $ : Nil ) # filter (\(Tuple _ v) → v /= 0.0) -data Duration = Duration DurationIn -type DurationIn = List (Tuple DurationComponent Number) - -derive instance eqDuration ∷ Eq Duration -instance showDuration ∷ Show Duration where - show (Duration d)= "(Duration " <> show d <> ")" - - data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds | Milliseconds instance showDurationComponent ∷ Show DurationComponent where @@ -111,22 +127,6 @@ instance showDurationComponent ∷ Show DurationComponent where derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent -appendComponents ∷ DurationIn → DurationIn → DurationIn -appendComponents Nil x = x -appendComponents x Nil = x -appendComponents ass@(a:as) bss@(b:bs) = case a, b of - Tuple aC aV, Tuple bC bV - | aC > bC → a : appendComponents as bss - | aC < bC → b : appendComponents ass bs - | otherwise → Tuple aC (aV + bV) : appendComponents as bs - -instance semigroupDuration ∷ Semigroup Duration where - append (Duration a) (Duration b) = Duration (appendComponents a b) - -instance monoidDuration ∷ Monoid Duration where - mempty = Duration mempty - - week ∷ Number → Duration week = Duration <<< pure <<< Tuple Day <<< (_ * 7.0) From 62bf3051d221b0264e134c8ba7c43ec0ffeee19f Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 5 Apr 2017 21:32:17 +0400 Subject: [PATCH 07/33] remove mkDuration DurationView and Milliseconds component --- src/Data/Interval/Interval.purs | 52 ++++++++++----------------------- test/Test/Main.purs | 13 ++------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index e0b27b2..007bb90 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -2,8 +2,6 @@ module Data.Interval ( Duration , Interval(..) , RecurringInterval(..) - , DurationView - , mkDuration , year , month , week @@ -22,7 +20,7 @@ import Data.Monoid (class Monoid, mempty) import Control.Extend (class Extend) import Data.Maybe (Maybe) -import Data.List (List(..), (:), filter) +import Data.List (List(..), (:)) import Data.Tuple (Tuple(..)) @@ -67,6 +65,7 @@ instance extendInterval ∷ Extend Interval where extend f a@(StartDuration x d) = StartDuration (f a) d extend f (JustDuration d) = JustDuration d + data Duration = Duration DurationIn type DurationIn = List (Tuple DurationComponent Number) @@ -90,30 +89,7 @@ appendComponents ass@(a:as) bss@(b:bs) = case a, b of | aC < bC → b : appendComponents ass bs | otherwise → Tuple aC (aV + bV) : appendComponents as bs - -type DurationView = - { year ∷ Number - , month ∷ Number - , day ∷ Number - , hours ∷ Number - , minutes ∷ Number - , seconds ∷ Number - , milliseconds ∷ Number - } - -mkDuration ∷ DurationView → Duration -mkDuration d = Duration $ - ( Tuple Year d.year - : Tuple Month d.month - : Tuple Day d.day - : Tuple Hours d.hours - : Tuple Minutes d.minutes - : Tuple Seconds d.seconds - : Tuple Milliseconds d.milliseconds - : Nil - ) # filter (\(Tuple _ v) → v /= 0.0) - -data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds | Milliseconds +data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds instance showDurationComponent ∷ Show DurationComponent where show Year = "Year" @@ -122,31 +98,35 @@ instance showDurationComponent ∷ Show DurationComponent where show Hours = "Hours" show Minutes = "Minutes" show Seconds = "Seconds" - show Milliseconds= "Millisecond" derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent + week ∷ Number → Duration -week = Duration <<< pure <<< Tuple Day <<< (_ * 7.0) +week = durationFromComponent Day <<< (_ * 7.0) year ∷ Number → Duration -year = Duration <<< pure <<< Tuple Year +year = durationFromComponent Year month ∷ Number → Duration -month = Duration <<< pure <<< Tuple Month +month = durationFromComponent Month day ∷ Number → Duration -day = Duration <<< pure <<< Tuple Day +day = durationFromComponent Day hours ∷ Number → Duration -hours = Duration <<< pure <<< Tuple Hours +hours = durationFromComponent Hours minutes ∷ Number → Duration -minutes = Duration <<< pure <<< Tuple Minutes +minutes = durationFromComponent Minutes seconds ∷ Number → Duration -seconds = Duration <<< pure <<< Tuple Seconds +seconds = durationFromComponent Seconds milliseconds ∷ Number → Duration -milliseconds = Duration <<< pure <<< Tuple Milliseconds +milliseconds = durationFromComponent Seconds <<< (_ / 1000.0) + +durationFromComponent ∷ DurationComponent → Number → Duration +durationFromComponent c 0.0 = mempty +durationFromComponent c n = Duration $ pure $ Tuple c n diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 019c530..ab0aaaf 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -27,16 +27,9 @@ type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit main :: Tests main = do log "check Duration monoid" - let id1 = Interval.mkDuration $ - { year: 1.0 - , month: 0.0 - , day: 0.0 - , hours: 0.0 - , minutes: 0.0 - , seconds: 0.0 - , milliseconds: 0.0 - } - assert $ id1 == (mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0)) + assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0) + assert $ Interval.seconds 0.5 == Interval.milliseconds 500.0 + assert $ Interval.week 1.0 == Interval.day 7.0 -- time -------------------------------------------------------------------- log "Check that Hour is a good BoundedEnum" From 089d9ef32967a044e1d936fb2ec4449cbf9d0891 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 5 Apr 2017 22:44:52 +0400 Subject: [PATCH 08/33] fis ord instance of DurationComponent --- src/Data/Interval/Interval.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 007bb90..28ecb6f 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -89,7 +89,7 @@ appendComponents ass@(a:as) bss@(b:bs) = case a, b of | aC < bC → b : appendComponents ass bs | otherwise → Tuple aC (aV + bV) : appendComponents as bs -data DurationComponent = Year | Month | Day | Hours | Minutes | Seconds +data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year instance showDurationComponent ∷ Show DurationComponent where show Year = "Year" From 266d4815b215ff11065d1d59c39d1e4dfb85312c Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Thu, 6 Apr 2017 16:50:45 +0400 Subject: [PATCH 09/33] make Interval Bifunctor --- src/Data/Interval/Interval.purs | 44 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 28ecb6f..25562fd 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -1,3 +1,5 @@ +-- TODO commiting this temporarly as depending on my fork of datetime is +-- not possibel as this module is not updated to ps@0.11 module Data.Interval ( Duration , Interval(..) @@ -13,38 +15,40 @@ module Data.Interval ) where import Prelude - -import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL) -import Data.Traversable (class Traversable, sequenceDefault) -import Data.Monoid (class Monoid, mempty) import Control.Extend (class Extend) - -import Data.Maybe (Maybe) +import Data.Bifunctor (class Bifunctor, bimap) +import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL) import Data.List (List(..), (:)) +import Data.Maybe (Maybe) +import Data.Monoid (class Monoid, mempty) +import Data.Traversable (class Traversable, sequenceDefault) import Data.Tuple (Tuple(..)) -data RecurringInterval a = RecurringInterval (Maybe Int) (Interval a) +data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) -data Interval a +data Interval d a = StartEnd a a - | DurationEnd Duration a - | StartDuration a Duration - | JustDuration Duration + | DurationEnd d a + | StartDuration a d + | JustDuration d -instance showInterval ∷ (Show a) => Show (Interval a) where +instance showInterval ∷ (Show d, Show a) => Show (Interval d a) where show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" show (StartDuration x d) = "(StartDuration " <> show x <> " " <> show d <> ")" show (JustDuration d) = "(JustDuration " <> show d <> ")" -instance functorInterval ∷ Functor Interval where - map f (StartEnd x y) = StartEnd (f x) (f y ) - map f (DurationEnd d x) = DurationEnd d (f x ) - map f (StartDuration x d) = StartDuration (f x) d - map _ (JustDuration d) = JustDuration d +instance functorInterval ∷ Functor (Interval d) where + map = bimap id + +instance bifunctorInterval ∷ Bifunctor Interval where + bimap _ f (StartEnd x y) = StartEnd (f x) (f y ) + bimap g f (DurationEnd d x) = DurationEnd (g d) (f x ) + bimap g f (StartDuration x d) = StartDuration (f x) (g d) + bimap g _ (JustDuration d) = JustDuration (g d) -instance foldableInterval ∷ Foldable Interval where +instance foldableInterval ∷ Foldable (Interval d) where foldl f z (StartEnd x y) = (z `f` x) `f` y foldl f z (DurationEnd d x) = z `f` x foldl f z (StartDuration x d) = z `f` x @@ -52,14 +56,14 @@ instance foldableInterval ∷ Foldable Interval where foldr x = foldrDefault x foldMap = foldMapDefaultL -instance traversableInterval ∷ Traversable Interval where +instance traversableInterval ∷ Traversable (Interval d) where traverse f (StartEnd x y) = StartEnd <$> f x <*> f y traverse f (DurationEnd d x) = f x <#> DurationEnd d traverse f (StartDuration x d) = f x <#> (_ `StartDuration` d) traverse _ (JustDuration d) = pure (JustDuration d) sequence = sequenceDefault -instance extendInterval ∷ Extend Interval where +instance extendInterval ∷ Extend (Interval d) where extend f a@(StartEnd x y) = StartEnd (f a) (f a ) extend f a@(DurationEnd d x) = DurationEnd d (f a ) extend f a@(StartDuration x d) = StartDuration (f a) d From 0a7b6285a880f839dac3efbbd9f16d36e6ad3c4f Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Thu, 6 Apr 2017 17:01:27 +0400 Subject: [PATCH 10/33] add Bifoldable for Interval --- src/Data/Interval/Interval.purs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 25562fd..5666489 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -18,6 +18,7 @@ import Prelude import Control.Extend (class Extend) import Data.Bifunctor (class Bifunctor, bimap) import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL) +import Data.Bifoldable (class Bifoldable, bifoldrDefault, bifoldMapDefaultL) import Data.List (List(..), (:)) import Data.Maybe (Maybe) import Data.Monoid (class Monoid, mempty) @@ -56,6 +57,14 @@ instance foldableInterval ∷ Foldable (Interval d) where foldr x = foldrDefault x foldMap = foldMapDefaultL +instance bifoldableInterval ∷ Bifoldable Interval where + bifoldl _ f z (StartEnd x y) = (z `f` x) `f` y + bifoldl g f z (DurationEnd d x) = (z `g` d) `f` x + bifoldl g f z (StartDuration x d) = (z `g` d) `f` x + bifoldl g _ z (JustDuration d) = z `g` d + bifoldr x = bifoldrDefault x + bifoldMap = bifoldMapDefaultL + instance traversableInterval ∷ Traversable (Interval d) where traverse f (StartEnd x y) = StartEnd <$> f x <*> f y traverse f (DurationEnd d x) = f x <#> DurationEnd d From 0ceb8eb4ac63b5b0d9ac4d72d5bf58373b2d07b9 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Thu, 6 Apr 2017 20:28:48 +0400 Subject: [PATCH 11/33] add IsoDuration; use Map instead of List Tuple --- bower.json | 3 +- src/Data/Interval/Interval.purs | 80 +++++++++++++++++++++------------ test/Test/Main.purs | 4 ++ 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/bower.json b/bower.json index f081396..102ed0b 100644 --- a/bower.json +++ b/bower.json @@ -20,7 +20,8 @@ "purescript-functions": "^3.0.0", "purescript-generics": "^4.0.0", "purescript-integers": "^3.0.0", - "purescript-math": "^2.0.0" + "purescript-math": "^2.0.0", + "purescript-maps": "^3.0.0" }, "devDependencies": { "purescript-assert": "^3.0.0", diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 5666489..6749c0f 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -1,9 +1,11 @@ --- TODO commiting this temporarly as depending on my fork of datetime is --- not possibel as this module is not updated to ps@0.11 module Data.Interval - ( Duration - , Interval(..) + ( Interval(..) , RecurringInterval(..) + , IsoDuration + , unIsoDuration + , mkIsoDuration + , isValidIsoDuration + , Duration , year , month , week @@ -15,15 +17,19 @@ module Data.Interval ) where import Prelude -import Control.Extend (class Extend) -import Data.Bifunctor (class Bifunctor, bimap) -import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL) +import Control.Extend (class Extend, (=>>)) +import Data.Foldable (class Foldable, fold, foldMap, foldrDefault, foldMapDefaultL) import Data.Bifoldable (class Bifoldable, bifoldrDefault, bifoldMapDefaultL) -import Data.List (List(..), (:)) -import Data.Maybe (Maybe) +import Data.Bifunctor (class Bifunctor, bimap) +import Data.List ((:), reverse) +import Data.Maybe (Maybe(..)) +import Data.Map as Map import Data.Monoid (class Monoid, mempty) +import Data.Monoid.Conj (Conj(..)) +import Data.Monoid.Additive (Additive(..)) import Data.Traversable (class Traversable, sequenceDefault) -import Data.Tuple (Tuple(..)) +import Data.Tuple (Tuple(..), snd) +import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) @@ -79,30 +85,51 @@ instance extendInterval ∷ Extend (Interval d) where extend f (JustDuration d) = JustDuration d -data Duration = Duration DurationIn -type DurationIn = List (Tuple DurationComponent Number) +mkIsoDuration ∷ Duration → Maybe IsoDuration +mkIsoDuration d | isValidIsoDuration d = Just $ IsoDuration d +mkIsoDuration _ = Nothing + +isFractional ∷ Number → Boolean +isFractional a = Math.floor a /= a + +-- allow only last number to be fractional +isValidIsoDuration ∷ Duration → Boolean +isValidIsoDuration (Duration m) = Map.toAscUnfoldable m + # reverse + =>> (validateFractionalUse >>> Conj) + # fold + # unConj + where + unConj (Conj a) = a + validateFractionalUse = case _ of + (Tuple _ n):as | isFractional n → foldMap (snd >>> Additive) as == mempty + _ → true + +unIsoDuration ∷ IsoDuration → Duration +unIsoDuration (IsoDuration a) = a + +data IsoDuration = IsoDuration Duration +derive instance eqIsoDuration ∷ Eq IsoDuration +instance showIsoDuration ∷ Show IsoDuration where + show (IsoDuration d)= "(IsoDuration " <> show d <> ")" + +data Duration = Duration (Map.Map DurationComponent Number) -- TODO `day 1 == hours 24` derive instance eqDuration ∷ Eq Duration + instance showDuration ∷ Show Duration where show (Duration d)= "(Duration " <> show d <> ")" instance semigroupDuration ∷ Semigroup Duration where - append (Duration a) (Duration b) = Duration (appendComponents a b) + append (Duration a) (Duration b) = Duration $ Map.unionWith (+) a b instance monoidDuration ∷ Monoid Duration where mempty = Duration mempty -appendComponents ∷ DurationIn → DurationIn → DurationIn -appendComponents Nil x = x -appendComponents x Nil = x -appendComponents ass@(a:as) bss@(b:bs) = case a, b of - Tuple aC aV, Tuple bC bV - | aC > bC → a : appendComponents as bss - | aC < bC → b : appendComponents ass bs - | otherwise → Tuple aC (aV + bV) : appendComponents as bs - data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year +derive instance eqDurationComponent ∷ Eq DurationComponent +derive instance ordDurationComponent ∷ Ord DurationComponent instance showDurationComponent ∷ Show DurationComponent where show Year = "Year" @@ -112,9 +139,6 @@ instance showDurationComponent ∷ Show DurationComponent where show Minutes = "Minutes" show Seconds = "Seconds" -derive instance eqDurationComponent ∷ Eq DurationComponent -derive instance ordDurationComponent ∷ Ord DurationComponent - week ∷ Number → Duration week = durationFromComponent Day <<< (_ * 7.0) @@ -140,6 +164,6 @@ seconds = durationFromComponent Seconds milliseconds ∷ Number → Duration milliseconds = durationFromComponent Seconds <<< (_ / 1000.0) -durationFromComponent ∷ DurationComponent → Number → Duration -durationFromComponent c 0.0 = mempty -durationFromComponent c n = Duration $ pure $ Tuple c n +durationFromComponent ∷ DurationComponent → Number → Duration +-- durationFromComponent _ 0.0 = mempty +durationFromComponent k v= Duration $ Map.singleton k v diff --git a/test/Test/Main.purs b/test/Test/Main.purs index ab0aaaf..73e5f1f 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -30,6 +30,10 @@ main = do assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0) assert $ Interval.seconds 0.5 == Interval.milliseconds 500.0 assert $ Interval.week 1.0 == Interval.day 7.0 + assert $ Interval.mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing + assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.seconds 0.0) /= Nothing + assert $ Interval.mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing + assert $ Interval.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing -- time -------------------------------------------------------------------- log "Check that Hour is a good BoundedEnum" From c6cbe3273b2aef61553e788913cedec6b86289fb Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 19 Apr 2017 01:17:15 +0400 Subject: [PATCH 12/33] derive instances for RecurringInterval --- src/Data/Interval/Interval.purs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 6749c0f..372733f 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -34,6 +34,35 @@ import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) +instance showRecurringInterval ∷ (Show d, Show a) => Show (RecurringInterval d a) where + show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" + +over :: ∀ d a d' a'. (Interval d a -> Interval d' a') -> RecurringInterval d a -> RecurringInterval d' a' +over f (RecurringInterval n i) = RecurringInterval n (f i) + +instance functorRecurringInterval ∷ Functor (RecurringInterval d) where + map = over $ bimap id + +instance bifunctorRecurringInterval ∷ Bifunctor RecurringInterval where + bimap = over $ bimap + +instance foldableInterval ∷ Foldable (Interval d) where + foldl = over $ foldl + foldr = over $ foldr + foldMap = foldMapDefaultL + +instance bifoldableInterval ∷ Bifoldable Interval where + bifoldl = over $ bifoldl + bifoldr = over $ bifoldr + bifoldMap = bifoldMapDefaultL + +instance traversableInterval ∷ Traversable (Interval d) where + traverse = over $ traverse + sequence = sequenceDefault + +instance extendInterval ∷ Extend (Interval d) where + extend = over $ extend + data Interval d a = StartEnd a a | DurationEnd d a From 503c6f865f941043955d60c98760be1850088eec Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 19 Apr 2017 02:27:20 +0400 Subject: [PATCH 13/33] fix derivations --- .travis.yml | 10 ++------- package.json | 5 +++-- src/Data/Interval/Interval.purs | 36 ++++++++++++++++----------------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index e06d3f0..3ee97af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,20 +2,14 @@ language: node_js dist: trusty sudo: required node_js: stable -env: - - PATH=$HOME/purescript:$PATH install: - - TAG=$(wget -q -O - https://github.com/purescript/purescript/releases/latest --server-response --max-redirect 0 2>&1 | sed -n -e 's/.*Location:.*tag\///p') - - wget -O $HOME/purescript.tar.gz https://github.com/purescript/purescript/releases/download/$TAG/linux64.tar.gz - - tar -xvf $HOME/purescript.tar.gz -C $HOME/ - - chmod a+x $HOME/purescript - npm install -g bower - npm install -script: - bower install --production +script: - npm run -s build - bower install - - npm test + - npm run -s test after_success: - >- test $TRAVIS_TAG && diff --git a/package.json b/package.json index 132cefc..e925ffc 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ }, "devDependencies": { "eslint": "^3.17.1", - "pulp": "^10.0.4", - "purescript-psa": "^0.5.0-rc.1", + "pulp": "^11.0.x", + "purescript": "0.11.x", + "purescript-psa": "^0.5.0", "rimraf": "^2.6.1" } } diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 372733f..0fc6bd2 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -17,9 +17,9 @@ module Data.Interval ) where import Prelude -import Control.Extend (class Extend, (=>>)) -import Data.Foldable (class Foldable, fold, foldMap, foldrDefault, foldMapDefaultL) -import Data.Bifoldable (class Bifoldable, bifoldrDefault, bifoldMapDefaultL) +import Control.Extend (class Extend, (=>>), extend) +import Data.Foldable (class Foldable, foldl, foldr, fold, foldMap, foldrDefault, foldMapDefaultL) +import Data.Bifoldable (class Bifoldable, bifoldl, bifoldr, bifoldrDefault, bifoldMapDefaultL) import Data.Bifunctor (class Bifunctor, bimap) import Data.List ((:), reverse) import Data.Maybe (Maybe(..)) @@ -27,7 +27,7 @@ import Data.Map as Map import Data.Monoid (class Monoid, mempty) import Data.Monoid.Conj (Conj(..)) import Data.Monoid.Additive (Additive(..)) -import Data.Traversable (class Traversable, sequenceDefault) +import Data.Traversable (class Traversable, traverse, sequenceDefault) import Data.Tuple (Tuple(..), snd) import Math as Math @@ -37,31 +37,31 @@ data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) instance showRecurringInterval ∷ (Show d, Show a) => Show (RecurringInterval d a) where show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" -over :: ∀ d a d' a'. (Interval d a -> Interval d' a') -> RecurringInterval d a -> RecurringInterval d' a' -over f (RecurringInterval n i) = RecurringInterval n (f i) +interval :: ∀ d a . RecurringInterval d a -> Interval d a +interval (RecurringInterval _ i) = i instance functorRecurringInterval ∷ Functor (RecurringInterval d) where - map = over $ bimap id + map f (RecurringInterval n i) = (RecurringInterval n (map f i)) instance bifunctorRecurringInterval ∷ Bifunctor RecurringInterval where - bimap = over $ bimap + bimap f g (RecurringInterval n i) = RecurringInterval n $ bimap f g i -instance foldableInterval ∷ Foldable (Interval d) where - foldl = over $ foldl - foldr = over $ foldr +instance foldableRecurringInterval ∷ Foldable (RecurringInterval d) where + foldl f i = foldl f i <<< interval + foldr f i = foldr f i <<< interval foldMap = foldMapDefaultL -instance bifoldableInterval ∷ Bifoldable Interval where - bifoldl = over $ bifoldl - bifoldr = over $ bifoldr +instance bifoldableRecurringInterval ∷ Bifoldable RecurringInterval where + bifoldl f g i = bifoldl f g i <<< interval + bifoldr f g i = bifoldr f g i <<< interval bifoldMap = bifoldMapDefaultL -instance traversableInterval ∷ Traversable (Interval d) where - traverse = over $ traverse +instance traversableRecurringInterval ∷ Traversable (RecurringInterval d) where + traverse f (RecurringInterval n i) = map (RecurringInterval n) $ traverse f i sequence = sequenceDefault -instance extendInterval ∷ Extend (Interval d) where - extend = over $ extend +instance extendRecurringInterval ∷ Extend (RecurringInterval d) where + extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const $ f a) i ) data Interval d a = StartEnd a a From 5d06e532805e3fdaed06dffad927d60d32ab230f Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 19 Apr 2017 22:06:34 +0400 Subject: [PATCH 14/33] add Bitraversable and Eq instances --- src/Data/Interval/Interval.purs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 0fc6bd2..2c7f6a3 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -21,6 +21,7 @@ import Control.Extend (class Extend, (=>>), extend) import Data.Foldable (class Foldable, foldl, foldr, fold, foldMap, foldrDefault, foldMapDefaultL) import Data.Bifoldable (class Bifoldable, bifoldl, bifoldr, bifoldrDefault, bifoldMapDefaultL) import Data.Bifunctor (class Bifunctor, bimap) +import Data.Bitraversable (class Bitraversable, bitraverse, bisequenceDefault) import Data.List ((:), reverse) import Data.Maybe (Maybe(..)) import Data.Map as Map @@ -34,12 +35,16 @@ import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) +derive instance eqRecurringInterval ∷ (Eq d, Eq a) => Eq (RecurringInterval d a) instance showRecurringInterval ∷ (Show d, Show a) => Show (RecurringInterval d a) where show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" interval :: ∀ d a . RecurringInterval d a -> Interval d a interval (RecurringInterval _ i) = i +over :: ∀ f d a d' a'. Functor f => (Interval d a -> f (Interval d' a')) -> RecurringInterval d a -> f (RecurringInterval d' a') +over f (RecurringInterval n i) = map (RecurringInterval n) (f i) + instance functorRecurringInterval ∷ Functor (RecurringInterval d) where map f (RecurringInterval n i) = (RecurringInterval n (map f i)) @@ -57,9 +62,13 @@ instance bifoldableRecurringInterval ∷ Bifoldable RecurringInterval where bifoldMap = bifoldMapDefaultL instance traversableRecurringInterval ∷ Traversable (RecurringInterval d) where - traverse f (RecurringInterval n i) = map (RecurringInterval n) $ traverse f i + traverse f i = (traverse f) `over` i sequence = sequenceDefault +instance bitraversableRecurringInterval :: Bitraversable RecurringInterval where + bitraverse l r i = (bitraverse l r) `over` i + bisequence = bisequenceDefault + instance extendRecurringInterval ∷ Extend (RecurringInterval d) where extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const $ f a) i ) @@ -69,6 +78,7 @@ data Interval d a | StartDuration a d | JustDuration d +derive instance eqInterval ∷ (Eq d, Eq a) => Eq (Interval d a) instance showInterval ∷ (Show d, Show a) => Show (Interval d a) where show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" @@ -107,6 +117,13 @@ instance traversableInterval ∷ Traversable (Interval d) where traverse _ (JustDuration d) = pure (JustDuration d) sequence = sequenceDefault +instance bitraversableInterval :: Bitraversable Interval where + bitraverse _ r (StartEnd x y) = StartEnd <$> r x <*> r y + bitraverse l r (DurationEnd d x) = DurationEnd <$> l d <*> r x + bitraverse l r (StartDuration x d) = StartDuration <$> r x <*> l d + bitraverse l _ (JustDuration d) = JustDuration <$> l d + bisequence = bisequenceDefault + instance extendInterval ∷ Extend (Interval d) where extend f a@(StartEnd x y) = StartEnd (f a) (f a ) extend f a@(DurationEnd d x) = DurationEnd d (f a ) From d2acbd6fbf172700aab9cc57f1bec6e4996bd4cb Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 25 Apr 2017 19:24:50 +0400 Subject: [PATCH 15/33] export Duration and DurationComponent --- src/Data/Interval/Interval.purs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 2c7f6a3..17d3758 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -2,6 +2,8 @@ module Data.Interval ( Interval(..) , RecurringInterval(..) , IsoDuration + , Duration(..) + , DurationComponent(..) , unIsoDuration , mkIsoDuration , isValidIsoDuration From 5f66a893403a772fe0b1436245ea93e19eb305ce Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Wed, 26 Apr 2017 14:06:24 +0400 Subject: [PATCH 16/33] make sure IsoDuraiton is not empty --- src/Data/Interval/Interval.purs | 19 ++++++++++--------- test/Test/Main.purs | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 17d3758..f6b2d2b 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -7,7 +7,6 @@ module Data.Interval , unIsoDuration , mkIsoDuration , isValidIsoDuration - , Duration , year , month , week @@ -32,9 +31,11 @@ import Data.Monoid.Conj (Conj(..)) import Data.Monoid.Additive (Additive(..)) import Data.Traversable (class Traversable, traverse, sequenceDefault) import Data.Tuple (Tuple(..), snd) +import Control.Comonad (extract) import Math as Math - +-- TODO read this lib for some helper function inspiration around intervals/durations +-- https://github.com/arnau/ISO8601/blob/master/spec/iso8601/duration_spec.rb data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) derive instance eqRecurringInterval ∷ (Eq d, Eq a) => Eq (RecurringInterval d a) @@ -140,15 +141,15 @@ mkIsoDuration _ = Nothing isFractional ∷ Number → Boolean isFractional a = Math.floor a /= a --- allow only last number to be fractional isValidIsoDuration ∷ Duration → Boolean -isValidIsoDuration (Duration m) = Map.toAscUnfoldable m - # reverse - =>> (validateFractionalUse >>> Conj) - # fold - # unConj +isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUse m) where - unConj (Conj a) = a + -- allow only last number to be fractional + hasValidFractionalUse = Map.toAscUnfoldable + >>> reverse + >>> (_ =>> (validateFractionalUse >>> Conj)) + >>> fold + >>> extract validateFractionalUse = case _ of (Tuple _ n):as | isFractional n → foldMap (snd >>> Additive) as == mempty _ → true diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 0979161..e7b7932 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -40,6 +40,7 @@ main = do assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.seconds 0.0) /= Nothing assert $ Interval.mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing assert $ Interval.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing + assert $ Interval.mkIsoDuration (mempty) == Nothing let epochDate = unsafePartial fromJust $ Date.canonicalDate <$> toEnum 1 From ea6396c4c1d0245511b7568766109a31bb721711 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Thu, 27 Apr 2017 01:20:28 +0400 Subject: [PATCH 17/33] add ^ to PS version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index e925ffc..94a6259 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "devDependencies": { "eslint": "^3.17.1", "pulp": "^11.0.x", - "purescript": "0.11.x", - "purescript-psa": "^0.5.0", + "purescript": "^0.11.x", + "purescript-psa": "^0.5.x", "rimraf": "^2.6.1" } } From e95b67f1013cc811454a4809c493633cabfed15b Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Thu, 27 Apr 2017 17:59:15 +0400 Subject: [PATCH 18/33] revert travis changes --- .travis.yml | 8 +++++++- package.json | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3ee97af..d980b08 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,17 @@ language: node_js dist: trusty sudo: required node_js: stable +env: + - PATH=$HOME/purescript:$PATH install: + - TAG=$(wget -q -O - https://github.com/purescript/purescript/releases/latest --server-response --max-redirect 0 2>&1 | sed -n -e 's/.*Location:.*tag\///p') + - wget -O $HOME/purescript.tar.gz https://github.com/purescript/purescript/releases/download/$TAG/linux64.tar.gz + - tar -xvf $HOME/purescript.tar.gz -C $HOME/ + - chmod a+x $HOME/purescript - npm install -g bower - npm install - - bower install --production script: + - bower install --production - npm run -s build - bower install - npm run -s test diff --git a/package.json b/package.json index 94a6259..017bc40 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "devDependencies": { "eslint": "^3.17.1", "pulp": "^11.0.x", - "purescript": "^0.11.x", "purescript-psa": "^0.5.x", "rimraf": "^2.6.1" } From 34640c6d4274dcd34e9d83b37d0d4b36aa79549e Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 16 May 2017 09:01:39 -0600 Subject: [PATCH 19/33] make Duration new type and derive Newype --- src/Data/Interval/Interval.purs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index f6b2d2b..28dcd16 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -31,6 +31,7 @@ import Data.Monoid.Conj (Conj(..)) import Data.Monoid.Additive (Additive(..)) import Data.Traversable (class Traversable, traverse, sequenceDefault) import Data.Tuple (Tuple(..), snd) +import Data.Newtype (class Newtype) import Control.Comonad (extract) import Math as Math @@ -42,10 +43,10 @@ derive instance eqRecurringInterval ∷ (Eq d, Eq a) => Eq (RecurringInterval d instance showRecurringInterval ∷ (Show d, Show a) => Show (RecurringInterval d a) where show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" -interval :: ∀ d a . RecurringInterval d a -> Interval d a +interval ∷ ∀ d a . RecurringInterval d a → Interval d a interval (RecurringInterval _ i) = i -over :: ∀ f d a d' a'. Functor f => (Interval d a -> f (Interval d' a')) -> RecurringInterval d a -> f (RecurringInterval d' a') +over ∷ ∀ f d a d' a'. Functor f => (Interval d a → f (Interval d' a')) → RecurringInterval d a → f (RecurringInterval d' a') over f (RecurringInterval n i) = map (RecurringInterval n) (f i) instance functorRecurringInterval ∷ Functor (RecurringInterval d) where @@ -68,7 +69,7 @@ instance traversableRecurringInterval ∷ Traversable (RecurringInterval d) wher traverse f i = (traverse f) `over` i sequence = sequenceDefault -instance bitraversableRecurringInterval :: Bitraversable RecurringInterval where +instance bitraversableRecurringInterval ∷ Bitraversable RecurringInterval where bitraverse l r i = (bitraverse l r) `over` i bisequence = bisequenceDefault @@ -120,7 +121,7 @@ instance traversableInterval ∷ Traversable (Interval d) where traverse _ (JustDuration d) = pure (JustDuration d) sequence = sequenceDefault -instance bitraversableInterval :: Bitraversable Interval where +instance bitraversableInterval ∷ Bitraversable Interval where bitraverse _ r (StartEnd x y) = StartEnd <$> r x <*> r y bitraverse l r (DurationEnd d x) = DurationEnd <$> l d <*> r x bitraverse l r (StartDuration x d) = StartDuration <$> r x <*> l d @@ -163,9 +164,10 @@ instance showIsoDuration ∷ Show IsoDuration where show (IsoDuration d)= "(IsoDuration " <> show d <> ")" -data Duration = Duration (Map.Map DurationComponent Number) +newtype Duration = Duration (Map.Map DurationComponent Number) -- TODO `day 1 == hours 24` derive instance eqDuration ∷ Eq Duration +derive instance newtypeDuration ∷ Newtype Duration _ instance showDuration ∷ Show Duration where show (Duration d)= "(Duration " <> show d <> ")" @@ -176,7 +178,7 @@ instance semigroupDuration ∷ Semigroup Duration where instance monoidDuration ∷ Monoid Duration where mempty = Duration mempty -data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year +data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent From 809a23437bf9d597847be0851c960b3ff006b246 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 16 May 2017 15:10:01 -0600 Subject: [PATCH 20/33] make duration components singular --- src/Data/Interval/Interval.purs | 34 ++++++++++++++++----------------- test/Test/Main.purs | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 28dcd16..92e47f8 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -11,10 +11,10 @@ module Data.Interval , month , week , day - , hours - , minutes - , seconds - , milliseconds + , hour + , minute + , second + , millisecond ) where import Prelude @@ -165,7 +165,7 @@ instance showIsoDuration ∷ Show IsoDuration where newtype Duration = Duration (Map.Map DurationComponent Number) --- TODO `day 1 == hours 24` +-- TODO `day 1 == hour 24` derive instance eqDuration ∷ Eq Duration derive instance newtypeDuration ∷ Newtype Duration _ @@ -178,7 +178,7 @@ instance semigroupDuration ∷ Semigroup Duration where instance monoidDuration ∷ Monoid Duration where mempty = Duration mempty -data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year +data DurationComponent = Second | Minute | Hour | Day | Month | Year derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent @@ -186,9 +186,9 @@ instance showDurationComponent ∷ Show DurationComponent where show Year = "Year" show Month = "Month" show Day = "Day" - show Hours = "Hours" - show Minutes = "Minutes" - show Seconds = "Seconds" + show Hour = "Hour" + show Minute = "Minute" + show Second = "Second" week ∷ Number → Duration @@ -203,17 +203,17 @@ month = durationFromComponent Month day ∷ Number → Duration day = durationFromComponent Day -hours ∷ Number → Duration -hours = durationFromComponent Hours +hour ∷ Number → Duration +hour = durationFromComponent Hour -minutes ∷ Number → Duration -minutes = durationFromComponent Minutes +minute ∷ Number → Duration +minute = durationFromComponent Minute -seconds ∷ Number → Duration -seconds = durationFromComponent Seconds +second ∷ Number → Duration +second = durationFromComponent Second -milliseconds ∷ Number → Duration -milliseconds = durationFromComponent Seconds <<< (_ / 1000.0) +millisecond ∷ Number → Duration +millisecond = durationFromComponent Second <<< (_ / 1000.0) durationFromComponent ∷ DurationComponent → Number → Duration -- durationFromComponent _ 0.0 = mempty diff --git a/test/Test/Main.purs b/test/Test/Main.purs index e7b7932..4f39a9a 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -34,10 +34,10 @@ main :: Tests main = do log "check Duration monoid" assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0) - assert $ Interval.seconds 0.5 == Interval.milliseconds 500.0 + assert $ Interval.second 0.5 == Interval.millisecond 500.0 assert $ Interval.week 1.0 == Interval.day 7.0 assert $ Interval.mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing - assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.seconds 0.0) /= Nothing + assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.second 0.0) /= Nothing assert $ Interval.mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing assert $ Interval.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing assert $ Interval.mkIsoDuration (mempty) == Nothing From 3eda0dd55721e9d4ba5d12805b19a905fcf46e83 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 16 May 2017 16:40:26 -0600 Subject: [PATCH 21/33] reverse duration component order --- src/Data/Interval/Interval.purs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 92e47f8..7ad305b 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -23,7 +23,7 @@ import Data.Foldable (class Foldable, foldl, foldr, fold, foldMap, foldrDefault, import Data.Bifoldable (class Bifoldable, bifoldl, bifoldr, bifoldrDefault, bifoldMapDefaultL) import Data.Bifunctor (class Bifunctor, bimap) import Data.Bitraversable (class Bitraversable, bitraverse, bisequenceDefault) -import Data.List ((:), reverse) +import Data.List ((:)) import Data.Maybe (Maybe(..)) import Data.Map as Map import Data.Monoid (class Monoid, mempty) @@ -147,7 +147,6 @@ isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUs where -- allow only last number to be fractional hasValidFractionalUse = Map.toAscUnfoldable - >>> reverse >>> (_ =>> (validateFractionalUse >>> Conj)) >>> fold >>> extract @@ -178,7 +177,7 @@ instance semigroupDuration ∷ Semigroup Duration where instance monoidDuration ∷ Monoid Duration where mempty = Duration mempty -data DurationComponent = Second | Minute | Hour | Day | Month | Year +data DurationComponent = Year | Month | Day | Hour | Minute | Second derive instance eqDurationComponent ∷ Eq DurationComponent derive instance ordDurationComponent ∷ Ord DurationComponent From 720cab7b1fb5650926d1420d1be0ffd5df7a0279 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 6 Jun 2017 15:11:56 +0400 Subject: [PATCH 22/33] make isoDuration newtype --- src/Data/Interval/Interval.purs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 7ad305b..edb1050 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -157,7 +157,7 @@ isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUs unIsoDuration ∷ IsoDuration → Duration unIsoDuration (IsoDuration a) = a -data IsoDuration = IsoDuration Duration +newtype IsoDuration = IsoDuration Duration derive instance eqIsoDuration ∷ Eq IsoDuration instance showIsoDuration ∷ Show IsoDuration where show (IsoDuration d)= "(IsoDuration " <> show d <> ")" From 5e7b7be14f136ab9bfbcfc26754e86cb17f282dc Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Tue, 6 Jun 2017 15:12:10 +0400 Subject: [PATCH 23/33] allow only positive values in duration --- src/Data/Interval/Interval.purs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index edb1050..c236643 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -145,14 +145,17 @@ isFractional a = Math.floor a /= a isValidIsoDuration ∷ Duration → Boolean isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUse m) where + isAllPositive = Map.toAscUnfoldable -- allow only last number to be fractional hasValidFractionalUse = Map.toAscUnfoldable - >>> (_ =>> (validateFractionalUse >>> Conj)) - >>> fold + >>> (\vals -> fold (vals =>> validateFractionalUse) <> positiveNums vals) >>> extract - validateFractionalUse = case _ of + validateFractionalUse vals = Conj $ case vals of (Tuple _ n):as | isFractional n → foldMap (snd >>> Additive) as == mempty _ → true + -- allow only positive values + positiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals + unIsoDuration ∷ IsoDuration → Duration unIsoDuration (IsoDuration a) = a From fbd30c4322577773e73688061c8bcb157fb78284 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 14:43:02 +0400 Subject: [PATCH 24/33] remove some TODOs --- src/Data/Interval/Interval.purs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index c236643..0f74c24 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -35,8 +35,6 @@ import Data.Newtype (class Newtype) import Control.Comonad (extract) import Math as Math --- TODO read this lib for some helper function inspiration around intervals/durations --- https://github.com/arnau/ISO8601/blob/master/spec/iso8601/duration_spec.rb data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) derive instance eqRecurringInterval ∷ (Eq d, Eq a) => Eq (RecurringInterval d a) @@ -167,7 +165,7 @@ instance showIsoDuration ∷ Show IsoDuration where newtype Duration = Duration (Map.Map DurationComponent Number) --- TODO `day 1 == hour 24` + derive instance eqDuration ∷ Eq Duration derive instance newtypeDuration ∷ Newtype Duration _ From 359e28a26d65cce86e9571308a9e41772d8aff0f Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 16:29:52 +0400 Subject: [PATCH 25/33] fix spaces and unicodes --- src/Data/Interval/Interval.purs | 115 ++++++++++++++++---------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 0f74c24..aef76f0 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -37,42 +37,42 @@ import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) -derive instance eqRecurringInterval ∷ (Eq d, Eq a) => Eq (RecurringInterval d a) -instance showRecurringInterval ∷ (Show d, Show a) => Show (RecurringInterval d a) where +derive instance eqRecurringInterval :: (Eq d, Eq a) => Eq (RecurringInterval d a) +instance showRecurringInterval :: (Show d, Show a) => Show (RecurringInterval d a) where show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" -interval ∷ ∀ d a . RecurringInterval d a → Interval d a +interval :: ∀ d a. RecurringInterval d a -> Interval d a interval (RecurringInterval _ i) = i -over ∷ ∀ f d a d' a'. Functor f => (Interval d a → f (Interval d' a')) → RecurringInterval d a → f (RecurringInterval d' a') +over :: ∀ f d a d' a'. Functor f => (Interval d a -> f (Interval d' a')) -> RecurringInterval d a -> f (RecurringInterval d' a') over f (RecurringInterval n i) = map (RecurringInterval n) (f i) -instance functorRecurringInterval ∷ Functor (RecurringInterval d) where +instance functorRecurringInterval :: Functor (RecurringInterval d) where map f (RecurringInterval n i) = (RecurringInterval n (map f i)) -instance bifunctorRecurringInterval ∷ Bifunctor RecurringInterval where +instance bifunctorRecurringInterval :: Bifunctor RecurringInterval where bimap f g (RecurringInterval n i) = RecurringInterval n $ bimap f g i -instance foldableRecurringInterval ∷ Foldable (RecurringInterval d) where +instance foldableRecurringInterval :: Foldable (RecurringInterval d) where foldl f i = foldl f i <<< interval foldr f i = foldr f i <<< interval foldMap = foldMapDefaultL -instance bifoldableRecurringInterval ∷ Bifoldable RecurringInterval where +instance bifoldableRecurringInterval :: Bifoldable RecurringInterval where bifoldl f g i = bifoldl f g i <<< interval bifoldr f g i = bifoldr f g i <<< interval bifoldMap = bifoldMapDefaultL -instance traversableRecurringInterval ∷ Traversable (RecurringInterval d) where +instance traversableRecurringInterval :: Traversable (RecurringInterval d) where traverse f i = (traverse f) `over` i sequence = sequenceDefault -instance bitraversableRecurringInterval ∷ Bitraversable RecurringInterval where +instance bitraversableRecurringInterval :: Bitraversable RecurringInterval where bitraverse l r i = (bitraverse l r) `over` i bisequence = bisequenceDefault -instance extendRecurringInterval ∷ Extend (RecurringInterval d) where - extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const $ f a) i ) +instance extendRecurringInterval :: Extend (RecurringInterval d) where + extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const $ f a) i) data Interval d a = StartEnd a a @@ -80,67 +80,67 @@ data Interval d a | StartDuration a d | JustDuration d -derive instance eqInterval ∷ (Eq d, Eq a) => Eq (Interval d a) -instance showInterval ∷ (Show d, Show a) => Show (Interval d a) where +derive instance eqInterval :: (Eq d, Eq a) => Eq (Interval d a) +instance showInterval :: (Show d, Show a) => Show (Interval d a) where show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" show (StartDuration x d) = "(StartDuration " <> show x <> " " <> show d <> ")" show (JustDuration d) = "(JustDuration " <> show d <> ")" -instance functorInterval ∷ Functor (Interval d) where +instance functorInterval :: Functor (Interval d) where map = bimap id -instance bifunctorInterval ∷ Bifunctor Interval where - bimap _ f (StartEnd x y) = StartEnd (f x) (f y ) - bimap g f (DurationEnd d x) = DurationEnd (g d) (f x ) +instance bifunctorInterval :: Bifunctor Interval where + bimap _ f (StartEnd x y) = StartEnd (f x) (f y) + bimap g f (DurationEnd d x) = DurationEnd (g d) (f x) bimap g f (StartDuration x d) = StartDuration (f x) (g d) bimap g _ (JustDuration d) = JustDuration (g d) -instance foldableInterval ∷ Foldable (Interval d) where +instance foldableInterval :: Foldable (Interval d) where foldl f z (StartEnd x y) = (z `f` x) `f` y foldl f z (DurationEnd d x) = z `f` x foldl f z (StartDuration x d) = z `f` x - foldl _ z _ = z + foldl _ z _ = z foldr x = foldrDefault x foldMap = foldMapDefaultL -instance bifoldableInterval ∷ Bifoldable Interval where +instance bifoldableInterval :: Bifoldable Interval where bifoldl _ f z (StartEnd x y) = (z `f` x) `f` y bifoldl g f z (DurationEnd d x) = (z `g` d) `f` x bifoldl g f z (StartDuration x d) = (z `g` d) `f` x - bifoldl g _ z (JustDuration d) = z `g` d + bifoldl g _ z (JustDuration d) = z `g` d bifoldr x = bifoldrDefault x bifoldMap = bifoldMapDefaultL -instance traversableInterval ∷ Traversable (Interval d) where +instance traversableInterval :: Traversable (Interval d) where traverse f (StartEnd x y) = StartEnd <$> f x <*> f y traverse f (DurationEnd d x) = f x <#> DurationEnd d traverse f (StartDuration x d) = f x <#> (_ `StartDuration` d) - traverse _ (JustDuration d) = pure (JustDuration d) + traverse _ (JustDuration d) = pure (JustDuration d) sequence = sequenceDefault -instance bitraversableInterval ∷ Bitraversable Interval where +instance bitraversableInterval :: Bitraversable Interval where bitraverse _ r (StartEnd x y) = StartEnd <$> r x <*> r y bitraverse l r (DurationEnd d x) = DurationEnd <$> l d <*> r x bitraverse l r (StartDuration x d) = StartDuration <$> r x <*> l d - bitraverse l _ (JustDuration d) = JustDuration <$> l d + bitraverse l _ (JustDuration d) = JustDuration <$> l d bisequence = bisequenceDefault -instance extendInterval ∷ Extend (Interval d) where - extend f a@(StartEnd x y) = StartEnd (f a) (f a ) - extend f a@(DurationEnd d x) = DurationEnd d (f a ) +instance extendInterval :: Extend (Interval d) where + extend f a@(StartEnd x y) = StartEnd (f a) (f a) + extend f a@(DurationEnd d x) = DurationEnd d (f a) extend f a@(StartDuration x d) = StartDuration (f a) d extend f (JustDuration d) = JustDuration d -mkIsoDuration ∷ Duration → Maybe IsoDuration +mkIsoDuration :: Duration -> Maybe IsoDuration mkIsoDuration d | isValidIsoDuration d = Just $ IsoDuration d mkIsoDuration _ = Nothing -isFractional ∷ Number → Boolean +isFractional :: Number -> Boolean isFractional a = Math.floor a /= a -isValidIsoDuration ∷ Duration → Boolean +isValidIsoDuration :: Duration -> Boolean isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUse m) where isAllPositive = Map.toAscUnfoldable @@ -149,40 +149,40 @@ isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUs >>> (\vals -> fold (vals =>> validateFractionalUse) <> positiveNums vals) >>> extract validateFractionalUse vals = Conj $ case vals of - (Tuple _ n):as | isFractional n → foldMap (snd >>> Additive) as == mempty - _ → true + (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty + _ -> true -- allow only positive values positiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals -unIsoDuration ∷ IsoDuration → Duration +unIsoDuration :: IsoDuration -> Duration unIsoDuration (IsoDuration a) = a newtype IsoDuration = IsoDuration Duration -derive instance eqIsoDuration ∷ Eq IsoDuration -instance showIsoDuration ∷ Show IsoDuration where - show (IsoDuration d)= "(IsoDuration " <> show d <> ")" +derive instance eqIsoDuration :: Eq IsoDuration +instance showIsoDuration :: Show IsoDuration where + show (IsoDuration d) = "(IsoDuration " <> show d <> ")" newtype Duration = Duration (Map.Map DurationComponent Number) -derive instance eqDuration ∷ Eq Duration -derive instance newtypeDuration ∷ Newtype Duration _ +derive instance eqDuration :: Eq Duration +derive instance newtypeDuration :: Newtype Duration _ -instance showDuration ∷ Show Duration where - show (Duration d)= "(Duration " <> show d <> ")" +instance showDuration :: Show Duration where + show (Duration d) = "(Duration " <> show d <> ")" -instance semigroupDuration ∷ Semigroup Duration where +instance semigroupDuration :: Semigroup Duration where append (Duration a) (Duration b) = Duration $ Map.unionWith (+) a b -instance monoidDuration ∷ Monoid Duration where +instance monoidDuration :: Monoid Duration where mempty = Duration mempty data DurationComponent = Year | Month | Day | Hour | Minute | Second -derive instance eqDurationComponent ∷ Eq DurationComponent -derive instance ordDurationComponent ∷ Ord DurationComponent +derive instance eqDurationComponent :: Eq DurationComponent +derive instance ordDurationComponent :: Ord DurationComponent -instance showDurationComponent ∷ Show DurationComponent where +instance showDurationComponent :: Show DurationComponent where show Year = "Year" show Month = "Month" show Day = "Day" @@ -191,30 +191,29 @@ instance showDurationComponent ∷ Show DurationComponent where show Second = "Second" -week ∷ Number → Duration +week :: Number -> Duration week = durationFromComponent Day <<< (_ * 7.0) -year ∷ Number → Duration +year :: Number -> Duration year = durationFromComponent Year -month ∷ Number → Duration +month :: Number -> Duration month = durationFromComponent Month -day ∷ Number → Duration +day :: Number -> Duration day = durationFromComponent Day -hour ∷ Number → Duration +hour :: Number -> Duration hour = durationFromComponent Hour -minute ∷ Number → Duration +minute :: Number -> Duration minute = durationFromComponent Minute -second ∷ Number → Duration +second :: Number -> Duration second = durationFromComponent Second -millisecond ∷ Number → Duration +millisecond :: Number -> Duration millisecond = durationFromComponent Second <<< (_ / 1000.0) -durationFromComponent ∷ DurationComponent → Number → Duration --- durationFromComponent _ 0.0 = mempty -durationFromComponent k v= Duration $ Map.singleton k v +durationFromComponent :: DurationComponent -> Number -> Duration +durationFromComponent k v = Duration $ Map.singleton k v From 355eb630ac1dc872fa7082675b10cff2d2214534 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 16:31:40 +0400 Subject: [PATCH 26/33] add ord instances --- src/Data/Interval/Interval.purs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index aef76f0..f36e122 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -38,6 +38,7 @@ import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) derive instance eqRecurringInterval :: (Eq d, Eq a) => Eq (RecurringInterval d a) +derive instance ordRecurringInterval :: (Ord d, Ord a) => Ord (RecurringInterval d a) instance showRecurringInterval :: (Show d, Show a) => Show (RecurringInterval d a) where show (RecurringInterval x y) = "(RecurringInterval " <> show x <> " " <> show y <> ")" @@ -81,6 +82,7 @@ data Interval d a | JustDuration d derive instance eqInterval :: (Eq d, Eq a) => Eq (Interval d a) +derive instance ordInterval :: (Ord d, Ord a) => Ord (Interval d a) instance showInterval :: (Show d, Show a) => Show (Interval d a) where show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" @@ -160,6 +162,7 @@ unIsoDuration (IsoDuration a) = a newtype IsoDuration = IsoDuration Duration derive instance eqIsoDuration :: Eq IsoDuration +derive instance ordIsoDuration :: Ord IsoDuration instance showIsoDuration :: Show IsoDuration where show (IsoDuration d) = "(IsoDuration " <> show d <> ")" @@ -167,6 +170,7 @@ instance showIsoDuration :: Show IsoDuration where newtype Duration = Duration (Map.Map DurationComponent Number) derive instance eqDuration :: Eq Duration +derive instance ordDuration :: Ord Duration derive instance newtypeDuration :: Newtype Duration _ instance showDuration :: Show Duration where From dfca68761af6aa9dcd3c47622e385d85cc572fd9 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 16:59:40 +0400 Subject: [PATCH 27/33] fix spacing, parens and $ usage --- src/Data/Interval/Interval.purs | 39 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index f36e122..5aaeba8 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -31,7 +31,7 @@ import Data.Monoid.Conj (Conj(..)) import Data.Monoid.Additive (Additive(..)) import Data.Traversable (class Traversable, traverse, sequenceDefault) import Data.Tuple (Tuple(..), snd) -import Data.Newtype (class Newtype) +import Data.Newtype (class Newtype, unwrap) import Control.Comonad (extract) import Math as Math @@ -49,10 +49,10 @@ over :: ∀ f d a d' a'. Functor f => (Interval d a -> f (Interval d' a')) -> Re over f (RecurringInterval n i) = map (RecurringInterval n) (f i) instance functorRecurringInterval :: Functor (RecurringInterval d) where - map f (RecurringInterval n i) = (RecurringInterval n (map f i)) + map f (RecurringInterval n i) = RecurringInterval n (map f i) instance bifunctorRecurringInterval :: Bifunctor RecurringInterval where - bimap f g (RecurringInterval n i) = RecurringInterval n $ bimap f g i + bimap f g (RecurringInterval n i) = RecurringInterval n (bimap f g i) instance foldableRecurringInterval :: Foldable (RecurringInterval d) where foldl f i = foldl f i <<< interval @@ -65,15 +65,15 @@ instance bifoldableRecurringInterval :: Bifoldable RecurringInterval where bifoldMap = bifoldMapDefaultL instance traversableRecurringInterval :: Traversable (RecurringInterval d) where - traverse f i = (traverse f) `over` i + traverse f i = traverse f `over` i sequence = sequenceDefault instance bitraversableRecurringInterval :: Bitraversable RecurringInterval where - bitraverse l r i = (bitraverse l r) `over` i + bitraverse l r i = bitraverse l r `over` i bisequence = bisequenceDefault instance extendRecurringInterval :: Extend (RecurringInterval d) where - extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const $ f a) i) + extend f a@(RecurringInterval n i) = RecurringInterval n (extend (const (f a)) i) data Interval d a = StartEnd a a @@ -136,25 +136,24 @@ instance extendInterval :: Extend (Interval d) where mkIsoDuration :: Duration -> Maybe IsoDuration -mkIsoDuration d | isValidIsoDuration d = Just $ IsoDuration d +mkIsoDuration d | isValidIsoDuration d = Just (IsoDuration d) mkIsoDuration _ = Nothing isFractional :: Number -> Boolean isFractional a = Math.floor a /= a isValidIsoDuration :: Duration -> Boolean -isValidIsoDuration (Duration m) = (not $ Map.isEmpty m) && (hasValidFractionalUse m) +isValidIsoDuration (Duration m) = not Map.isEmpty m && hasValidFractionalUse m where - isAllPositive = Map.toAscUnfoldable - -- allow only last number to be fractional - hasValidFractionalUse = Map.toAscUnfoldable - >>> (\vals -> fold (vals =>> validateFractionalUse) <> positiveNums vals) - >>> extract - validateFractionalUse vals = Conj $ case vals of - (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty - _ -> true - -- allow only positive values - positiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals + -- allow only last number to be fractional + hasValidFractionalUse = Map.toAscUnfoldable + >>> (\vals -> fold (vals =>> validateFractionalUse) <> positiveNums vals) + >>> extract + validateFractionalUse vals = Conj case vals of + (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty + _ -> true + -- allow only positive values + positiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals unIsoDuration :: IsoDuration -> Duration @@ -177,7 +176,7 @@ instance showDuration :: Show Duration where show (Duration d) = "(Duration " <> show d <> ")" instance semigroupDuration :: Semigroup Duration where - append (Duration a) (Duration b) = Duration $ Map.unionWith (+) a b + append (Duration a) (Duration b) = Duration (Map.unionWith (+) a b) instance monoidDuration :: Monoid Duration where mempty = Duration mempty @@ -220,4 +219,4 @@ millisecond :: Number -> Duration millisecond = durationFromComponent Second <<< (_ / 1000.0) durationFromComponent :: DurationComponent -> Number -> Duration -durationFromComponent k v = Duration $ Map.singleton k v +durationFromComponent k v = Duration (Map.singleton k v) From c3817cc82e78f4d86b9fc0465ed238d9845eae30 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 17:11:17 +0400 Subject: [PATCH 28/33] rename JustDuration to DurationOnly --- src/Data/Interval/Interval.purs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval/Interval.purs index 5aaeba8..6aedb69 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval/Interval.purs @@ -79,7 +79,7 @@ data Interval d a = StartEnd a a | DurationEnd d a | StartDuration a d - | JustDuration d + | DurationOnly d derive instance eqInterval :: (Eq d, Eq a) => Eq (Interval d a) derive instance ordInterval :: (Ord d, Ord a) => Ord (Interval d a) @@ -87,7 +87,7 @@ instance showInterval :: (Show d, Show a) => Show (Interval d a) where show (StartEnd x y) = "(StartEnd " <> show x <> " " <> show y <> ")" show (DurationEnd d x) = "(DurationEnd " <> show d <> " " <> show x <> ")" show (StartDuration x d) = "(StartDuration " <> show x <> " " <> show d <> ")" - show (JustDuration d) = "(JustDuration " <> show d <> ")" + show (DurationOnly d) = "(DurationOnly " <> show d <> ")" instance functorInterval :: Functor (Interval d) where map = bimap id @@ -96,7 +96,7 @@ instance bifunctorInterval :: Bifunctor Interval where bimap _ f (StartEnd x y) = StartEnd (f x) (f y) bimap g f (DurationEnd d x) = DurationEnd (g d) (f x) bimap g f (StartDuration x d) = StartDuration (f x) (g d) - bimap g _ (JustDuration d) = JustDuration (g d) + bimap g _ (DurationOnly d) = DurationOnly (g d) instance foldableInterval :: Foldable (Interval d) where foldl f z (StartEnd x y) = (z `f` x) `f` y @@ -110,7 +110,7 @@ instance bifoldableInterval :: Bifoldable Interval where bifoldl _ f z (StartEnd x y) = (z `f` x) `f` y bifoldl g f z (DurationEnd d x) = (z `g` d) `f` x bifoldl g f z (StartDuration x d) = (z `g` d) `f` x - bifoldl g _ z (JustDuration d) = z `g` d + bifoldl g _ z (DurationOnly d) = z `g` d bifoldr x = bifoldrDefault x bifoldMap = bifoldMapDefaultL @@ -118,21 +118,21 @@ instance traversableInterval :: Traversable (Interval d) where traverse f (StartEnd x y) = StartEnd <$> f x <*> f y traverse f (DurationEnd d x) = f x <#> DurationEnd d traverse f (StartDuration x d) = f x <#> (_ `StartDuration` d) - traverse _ (JustDuration d) = pure (JustDuration d) + traverse _ (DurationOnly d) = pure (DurationOnly d) sequence = sequenceDefault instance bitraversableInterval :: Bitraversable Interval where bitraverse _ r (StartEnd x y) = StartEnd <$> r x <*> r y bitraverse l r (DurationEnd d x) = DurationEnd <$> l d <*> r x bitraverse l r (StartDuration x d) = StartDuration <$> r x <*> l d - bitraverse l _ (JustDuration d) = JustDuration <$> l d + bitraverse l _ (DurationOnly d) = DurationOnly <$> l d bisequence = bisequenceDefault instance extendInterval :: Extend (Interval d) where extend f a@(StartEnd x y) = StartEnd (f a) (f a) extend f a@(DurationEnd d x) = DurationEnd d (f a) extend f a@(StartDuration x d) = StartDuration (f a) d - extend f (JustDuration d) = JustDuration d + extend f (DurationOnly d) = DurationOnly d mkIsoDuration :: Duration -> Maybe IsoDuration From d9457d22fa0e052084cc079f3ad84cff14d3a3ed Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 17:55:05 +0400 Subject: [PATCH 29/33] split Interval - move Interval.purs up one level - move Duration and IsoDuration parts away --- src/Data/{Interval => }/Interval.purs | 118 ++------------------------ src/Data/Interval/Duration.purs | 72 ++++++++++++++++ src/Data/Interval/Duration/Iso.purs | 56 ++++++++++++ test/Test/Main.purs | 11 +-- 4 files changed, 139 insertions(+), 118 deletions(-) rename src/Data/{Interval => }/Interval.purs (58%) create mode 100644 src/Data/Interval/Duration.purs create mode 100644 src/Data/Interval/Duration/Iso.purs diff --git a/src/Data/Interval/Interval.purs b/src/Data/Interval.purs similarity index 58% rename from src/Data/Interval/Interval.purs rename to src/Data/Interval.purs index 6aedb69..11081ef 100644 --- a/src/Data/Interval/Interval.purs +++ b/src/Data/Interval.purs @@ -1,39 +1,18 @@ module Data.Interval ( Interval(..) , RecurringInterval(..) - , IsoDuration - , Duration(..) - , DurationComponent(..) - , unIsoDuration - , mkIsoDuration - , isValidIsoDuration - , year - , month - , week - , day - , hour - , minute - , second - , millisecond + , module DurationExports ) where import Prelude -import Control.Extend (class Extend, (=>>), extend) -import Data.Foldable (class Foldable, foldl, foldr, fold, foldMap, foldrDefault, foldMapDefaultL) +import Data.Interval.Duration as DurationExports +import Control.Extend (class Extend, extend) +import Data.Foldable (class Foldable, foldl, foldr, foldrDefault, foldMapDefaultL) import Data.Bifoldable (class Bifoldable, bifoldl, bifoldr, bifoldrDefault, bifoldMapDefaultL) import Data.Bifunctor (class Bifunctor, bimap) import Data.Bitraversable (class Bitraversable, bitraverse, bisequenceDefault) -import Data.List ((:)) -import Data.Maybe (Maybe(..)) -import Data.Map as Map -import Data.Monoid (class Monoid, mempty) -import Data.Monoid.Conj (Conj(..)) -import Data.Monoid.Additive (Additive(..)) +import Data.Maybe (Maybe) import Data.Traversable (class Traversable, traverse, sequenceDefault) -import Data.Tuple (Tuple(..), snd) -import Data.Newtype (class Newtype, unwrap) -import Control.Comonad (extract) -import Math as Math data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a) @@ -133,90 +112,3 @@ instance extendInterval :: Extend (Interval d) where extend f a@(DurationEnd d x) = DurationEnd d (f a) extend f a@(StartDuration x d) = StartDuration (f a) d extend f (DurationOnly d) = DurationOnly d - - -mkIsoDuration :: Duration -> Maybe IsoDuration -mkIsoDuration d | isValidIsoDuration d = Just (IsoDuration d) -mkIsoDuration _ = Nothing - -isFractional :: Number -> Boolean -isFractional a = Math.floor a /= a - -isValidIsoDuration :: Duration -> Boolean -isValidIsoDuration (Duration m) = not Map.isEmpty m && hasValidFractionalUse m - where - -- allow only last number to be fractional - hasValidFractionalUse = Map.toAscUnfoldable - >>> (\vals -> fold (vals =>> validateFractionalUse) <> positiveNums vals) - >>> extract - validateFractionalUse vals = Conj case vals of - (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty - _ -> true - -- allow only positive values - positiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals - - -unIsoDuration :: IsoDuration -> Duration -unIsoDuration (IsoDuration a) = a - -newtype IsoDuration = IsoDuration Duration -derive instance eqIsoDuration :: Eq IsoDuration -derive instance ordIsoDuration :: Ord IsoDuration -instance showIsoDuration :: Show IsoDuration where - show (IsoDuration d) = "(IsoDuration " <> show d <> ")" - - -newtype Duration = Duration (Map.Map DurationComponent Number) - -derive instance eqDuration :: Eq Duration -derive instance ordDuration :: Ord Duration -derive instance newtypeDuration :: Newtype Duration _ - -instance showDuration :: Show Duration where - show (Duration d) = "(Duration " <> show d <> ")" - -instance semigroupDuration :: Semigroup Duration where - append (Duration a) (Duration b) = Duration (Map.unionWith (+) a b) - -instance monoidDuration :: Monoid Duration where - mempty = Duration mempty - -data DurationComponent = Year | Month | Day | Hour | Minute | Second -derive instance eqDurationComponent :: Eq DurationComponent -derive instance ordDurationComponent :: Ord DurationComponent - -instance showDurationComponent :: Show DurationComponent where - show Year = "Year" - show Month = "Month" - show Day = "Day" - show Hour = "Hour" - show Minute = "Minute" - show Second = "Second" - - -week :: Number -> Duration -week = durationFromComponent Day <<< (_ * 7.0) - -year :: Number -> Duration -year = durationFromComponent Year - -month :: Number -> Duration -month = durationFromComponent Month - -day :: Number -> Duration -day = durationFromComponent Day - -hour :: Number -> Duration -hour = durationFromComponent Hour - -minute :: Number -> Duration -minute = durationFromComponent Minute - -second :: Number -> Duration -second = durationFromComponent Second - -millisecond :: Number -> Duration -millisecond = durationFromComponent Second <<< (_ / 1000.0) - -durationFromComponent :: DurationComponent -> Number -> Duration -durationFromComponent k v = Duration (Map.singleton k v) diff --git a/src/Data/Interval/Duration.purs b/src/Data/Interval/Duration.purs new file mode 100644 index 0000000..b04a2d2 --- /dev/null +++ b/src/Data/Interval/Duration.purs @@ -0,0 +1,72 @@ +module Data.Interval.Duration + ( Duration(..) + , DurationComponent(..) + , year + , month + , week + , day + , hour + , minute + , second + , millisecond + ) where + +import Prelude +import Data.Map as Map +import Data.Monoid (class Monoid, mempty) +import Data.Newtype (class Newtype) + +newtype Duration = Duration (Map.Map DurationComponent Number) + +derive instance eqDuration :: Eq Duration +derive instance ordDuration :: Ord Duration +derive instance newtypeDuration :: Newtype Duration _ + +instance showDuration :: Show Duration where + show (Duration d) = "(Duration " <> show d <> ")" + +instance semigroupDuration :: Semigroup Duration where + append (Duration a) (Duration b) = Duration (Map.unionWith (+) a b) + +instance monoidDuration :: Monoid Duration where + mempty = Duration mempty + +data DurationComponent = Year | Month | Day | Hour | Minute | Second +derive instance eqDurationComponent :: Eq DurationComponent +derive instance ordDurationComponent :: Ord DurationComponent + +instance showDurationComponent :: Show DurationComponent where + show Year = "Year" + show Month = "Month" + show Day = "Day" + show Hour = "Hour" + show Minute = "Minute" + show Second = "Second" + + +week :: Number -> Duration +week = durationFromComponent Day <<< (_ * 7.0) + +year :: Number -> Duration +year = durationFromComponent Year + +month :: Number -> Duration +month = durationFromComponent Month + +day :: Number -> Duration +day = durationFromComponent Day + +hour :: Number -> Duration +hour = durationFromComponent Hour + +minute :: Number -> Duration +minute = durationFromComponent Minute + +second :: Number -> Duration +second = durationFromComponent Second + +millisecond :: Number -> Duration +millisecond = durationFromComponent Second <<< (_ / 1000.0) + +durationFromComponent :: DurationComponent -> Number -> Duration +durationFromComponent k v = Duration (Map.singleton k v) diff --git a/src/Data/Interval/Duration/Iso.purs b/src/Data/Interval/Duration/Iso.purs new file mode 100644 index 0000000..025e79f --- /dev/null +++ b/src/Data/Interval/Duration/Iso.purs @@ -0,0 +1,56 @@ +module Data.Interval.Duration.Iso + ( IsoDuration + , unIsoDuration + , mkIsoDuration + , isValidIsoDuration + ) where + +import Prelude +import Control.Extend ((=>>)) +import Data.Foldable (fold, foldMap) +import Data.Interval.Duration (Duration(..)) +import Data.List (List, (:)) +import Data.Maybe (Maybe(..)) +import Data.Map as Map +import Data.Monoid (mempty) +import Data.Monoid.Conj (Conj(..)) +import Data.Monoid.Additive (Additive(..)) +import Data.Tuple (Tuple(..), snd) +import Control.Comonad (extract) +import Math as Math + +newtype IsoDuration = IsoDuration Duration + +derive instance eqIsoDuration :: Eq IsoDuration +derive instance ordIsoDuration :: Ord IsoDuration +instance showIsoDuration :: Show IsoDuration where + show (IsoDuration d) = "(IsoDuration " <> show d <> ")" + + +unIsoDuration :: IsoDuration -> Duration +unIsoDuration (IsoDuration a) = a + +mkIsoDuration :: Duration -> Maybe IsoDuration +mkIsoDuration d | isValidIsoDuration d = Just (IsoDuration d) +mkIsoDuration _ = Nothing + +-- allow only positive numbers +-- allow only last number to be fractional +isValidIsoDuration :: Duration -> Boolean +isValidIsoDuration (Duration m) = not Map.isEmpty m && validNumberUsage m + where + isFractional :: Number -> Boolean + isFractional a = Math.floor a /= a + + validNumberUsage :: forall a. Map.Map a Number -> Boolean + validNumberUsage = Map.toAscUnfoldable + >>> (\vals -> fold (vals =>> hasValidFractionalUse) <> hasOnlyPositiveNums vals) + >>> extract + + hasValidFractionalUse :: forall a. List (Tuple a Number) -> Conj Boolean + hasValidFractionalUse vals = Conj case vals of + (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty + _ -> true + + hasOnlyPositiveNums :: forall a. List (Tuple a Number) -> Conj Boolean + hasOnlyPositiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 4f39a9a..2d716a3 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -10,6 +10,7 @@ import Data.Date as Date import Data.Time as Time import Data.Time.Duration as Duration import Data.Interval as Interval +import Data.Interval.Duration.Iso (mkIsoDuration) import Data.Array as Array import Data.DateTime as DateTime import Data.DateTime.Locale as Locale @@ -36,11 +37,11 @@ main = do assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0) assert $ Interval.second 0.5 == Interval.millisecond 500.0 assert $ Interval.week 1.0 == Interval.day 7.0 - assert $ Interval.mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing - assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.second 0.0) /= Nothing - assert $ Interval.mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing - assert $ Interval.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing - assert $ Interval.mkIsoDuration (mempty) == Nothing + assert $ mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing + assert $ mkIsoDuration (Interval.week 1.2 <> Interval.second 0.0) /= Nothing + assert $ mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing + assert $ mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing + assert $ mkIsoDuration (mempty) == Nothing let epochDate = unsafePartial fromJust $ Date.canonicalDate <$> toEnum 1 From 447406aace013238e1340c63b6d44f5bcc44aaee Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 18:00:41 +0400 Subject: [PATCH 30/33] reverse DurationComponent order --- src/Data/Interval/Duration.purs | 2 +- src/Data/Interval/Duration/Iso.purs | 3 ++- test/Test/Main.purs | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Data/Interval/Duration.purs b/src/Data/Interval/Duration.purs index b04a2d2..b45b1e5 100644 --- a/src/Data/Interval/Duration.purs +++ b/src/Data/Interval/Duration.purs @@ -31,7 +31,7 @@ instance semigroupDuration :: Semigroup Duration where instance monoidDuration :: Monoid Duration where mempty = Duration mempty -data DurationComponent = Year | Month | Day | Hour | Minute | Second +data DurationComponent = Second | Minute | Hour | Day | Month | Year derive instance eqDurationComponent :: Eq DurationComponent derive instance ordDurationComponent :: Ord DurationComponent diff --git a/src/Data/Interval/Duration/Iso.purs b/src/Data/Interval/Duration/Iso.purs index 025e79f..f01e156 100644 --- a/src/Data/Interval/Duration/Iso.purs +++ b/src/Data/Interval/Duration/Iso.purs @@ -9,7 +9,7 @@ import Prelude import Control.Extend ((=>>)) import Data.Foldable (fold, foldMap) import Data.Interval.Duration (Duration(..)) -import Data.List (List, (:)) +import Data.List (List, (:), reverse) import Data.Maybe (Maybe(..)) import Data.Map as Map import Data.Monoid (mempty) @@ -44,6 +44,7 @@ isValidIsoDuration (Duration m) = not Map.isEmpty m && validNumberUsage m validNumberUsage :: forall a. Map.Map a Number -> Boolean validNumberUsage = Map.toAscUnfoldable + >>> reverse >>> (\vals -> fold (vals =>> hasValidFractionalUse) <> hasOnlyPositiveNums vals) >>> extract diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 2d716a3..02f60e8 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -41,6 +41,7 @@ main = do assert $ mkIsoDuration (Interval.week 1.2 <> Interval.second 0.0) /= Nothing assert $ mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing assert $ mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing + assert $ mkIsoDuration (Interval.year 2.0 <> Interval.week (-1.0)) == Nothing assert $ mkIsoDuration (mempty) == Nothing let epochDate = unsafePartial fromJust $ Date.canonicalDate From d829b8c7f80bb03f6197308780164c163b27461a Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 21:23:22 +0400 Subject: [PATCH 31/33] add Week component to Duration; refactor Duration.Iso --- src/Data/Interval.purs | 5 +- src/Data/Interval/Duration.purs | 14 +++-- src/Data/Interval/Duration/Iso.purs | 86 +++++++++++++++++++---------- test/Test/Main.purs | 43 ++++++++------- 4 files changed, 92 insertions(+), 56 deletions(-) diff --git a/src/Data/Interval.purs b/src/Data/Interval.purs index 11081ef..d3c75ad 100644 --- a/src/Data/Interval.purs +++ b/src/Data/Interval.purs @@ -5,12 +5,13 @@ module Data.Interval ) where import Prelude -import Data.Interval.Duration as DurationExports + import Control.Extend (class Extend, extend) -import Data.Foldable (class Foldable, foldl, foldr, foldrDefault, foldMapDefaultL) import Data.Bifoldable (class Bifoldable, bifoldl, bifoldr, bifoldrDefault, bifoldMapDefaultL) import Data.Bifunctor (class Bifunctor, bimap) import Data.Bitraversable (class Bitraversable, bitraverse, bisequenceDefault) +import Data.Foldable (class Foldable, foldl, foldr, foldrDefault, foldMapDefaultL) +import Data.Interval.Duration as DurationExports import Data.Maybe (Maybe) import Data.Traversable (class Traversable, traverse, sequenceDefault) diff --git a/src/Data/Interval/Duration.purs b/src/Data/Interval/Duration.purs index b45b1e5..9af57e4 100644 --- a/src/Data/Interval/Duration.purs +++ b/src/Data/Interval/Duration.purs @@ -12,6 +12,7 @@ module Data.Interval.Duration ) where import Prelude + import Data.Map as Map import Data.Monoid (class Monoid, mempty) import Data.Newtype (class Newtype) @@ -31,21 +32,22 @@ instance semigroupDuration :: Semigroup Duration where instance monoidDuration :: Monoid Duration where mempty = Duration mempty -data DurationComponent = Second | Minute | Hour | Day | Month | Year +data DurationComponent = Second | Minute | Hour | Day | Week | Month | Year derive instance eqDurationComponent :: Eq DurationComponent derive instance ordDurationComponent :: Ord DurationComponent instance showDurationComponent :: Show DurationComponent where - show Year = "Year" - show Month = "Month" - show Day = "Day" - show Hour = "Hour" show Minute = "Minute" show Second = "Second" + show Hour = "Hour" + show Day = "Day" + show Week = "Week" + show Month = "Month" + show Year = "Year" week :: Number -> Duration -week = durationFromComponent Day <<< (_ * 7.0) +week = durationFromComponent Week year :: Number -> Duration year = durationFromComponent Year diff --git a/src/Data/Interval/Duration/Iso.purs b/src/Data/Interval/Duration/Iso.purs index f01e156..c9b8293 100644 --- a/src/Data/Interval/Duration/Iso.purs +++ b/src/Data/Interval/Duration/Iso.purs @@ -2,21 +2,23 @@ module Data.Interval.Duration.Iso ( IsoDuration , unIsoDuration , mkIsoDuration - , isValidIsoDuration + , Error(..) + , Errors ) where import Prelude -import Control.Extend ((=>>)) + +import Data.Array (uncons) +import Data.Either (Either(..)) import Data.Foldable (fold, foldMap) -import Data.Interval.Duration (Duration(..)) -import Data.List (List, (:), reverse) -import Data.Maybe (Maybe(..)) +import Data.Interval.Duration (Duration(..), DurationComponent(..)) +import Data.List (List(..), reverse, span, null) import Data.Map as Map -import Data.Monoid (mempty) -import Data.Monoid.Conj (Conj(..)) +import Data.Maybe (Maybe(..), isJust) import Data.Monoid.Additive (Additive(..)) +import Data.Newtype (unwrap) +import Data.NonEmpty (NonEmpty(..)) import Data.Tuple (Tuple(..), snd) -import Control.Comonad (extract) import Math as Math newtype IsoDuration = IsoDuration Duration @@ -26,32 +28,60 @@ derive instance ordIsoDuration :: Ord IsoDuration instance showIsoDuration :: Show IsoDuration where show (IsoDuration d) = "(IsoDuration " <> show d <> ")" +type Errors = NonEmpty Array Error + +data Error + = IsEmpty + | InvalidWeekComponentUsage + | ContainsNegativeValue DurationComponent + | InvalidFractionalUse DurationComponent + +derive instance eqError :: Eq Error +derive instance ordError :: Ord Error +instance showError :: Show Error where + show (IsEmpty) = "(IsEmpty)" + show (InvalidWeekComponentUsage) = "(InvalidWeekComponentUsage)" + show (ContainsNegativeValue c) = "(ContainsNegativeValue " <> show c <> ")" + show (InvalidFractionalUse c) = "(InvalidFractionalUse " <> show c <> ")" unIsoDuration :: IsoDuration -> Duration unIsoDuration (IsoDuration a) = a -mkIsoDuration :: Duration -> Maybe IsoDuration -mkIsoDuration d | isValidIsoDuration d = Just (IsoDuration d) -mkIsoDuration _ = Nothing +mkIsoDuration :: Duration -> Either Errors IsoDuration +mkIsoDuration d = case uncons (checkValidIsoDuration d) of + Just {head, tail} -> Left (NonEmpty head tail) + Nothing -> Right (IsoDuration d) --- allow only positive numbers --- allow only last number to be fractional -isValidIsoDuration :: Duration -> Boolean -isValidIsoDuration (Duration m) = not Map.isEmpty m && validNumberUsage m +checkValidIsoDuration :: Duration -> Array Error +checkValidIsoDuration (Duration asMap) = check {asList, asMap} where - isFractional :: Number -> Boolean - isFractional a = Math.floor a /= a + asList = reverse (Map.toAscUnfoldable asMap) + check = fold + [ checkEmptiness + , checkFractionalUse + , checkNegativeValues + , checkWeekUsage] + - validNumberUsage :: forall a. Map.Map a Number -> Boolean - validNumberUsage = Map.toAscUnfoldable - >>> reverse - >>> (\vals -> fold (vals =>> hasValidFractionalUse) <> hasOnlyPositiveNums vals) - >>> extract +type CheckEnv = + { asList :: List (Tuple DurationComponent Number) + , asMap :: Map.Map DurationComponent Number} - hasValidFractionalUse :: forall a. List (Tuple a Number) -> Conj Boolean - hasValidFractionalUse vals = Conj case vals of - (Tuple _ n):as | isFractional n -> foldMap (snd >>> Additive) as == mempty - _ -> true +checkWeekUsage :: CheckEnv -> Array Error +checkWeekUsage {asMap} = if isJust (Map.lookup Week asMap) && Map.size asMap > 1 + then [InvalidWeekComponentUsage] else [] + +checkEmptiness :: CheckEnv -> Array Error +checkEmptiness {asList} = if null asList then [IsEmpty] else [] + +checkFractionalUse :: CheckEnv -> Array Error +checkFractionalUse {asList} = case _.rest (span (snd >>> not isFractional) asList) of + Cons (Tuple c _) rest | checkRest rest -> [InvalidFractionalUse c] + _ -> [] + where + isFractional a = Math.floor a /= a + checkRest rest = unwrap (foldMap (snd >>> Math.abs >>> Additive) rest) > 0.0 - hasOnlyPositiveNums :: forall a. List (Tuple a Number) -> Conj Boolean - hasOnlyPositiveNums vals = foldMap (snd >>> (_ >= 0.0) >>> Conj) vals +checkNegativeValues :: CheckEnv -> Array Error +checkNegativeValues {asList} = flip foldMap asList \(Tuple c num) -> + if num >= 0.0 then [] else [ContainsNegativeValue c] diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 02f60e8..4dafb23 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -4,29 +4,28 @@ import Prelude import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE, log) - -import Data.Enum (class BoundedEnum, Cardinality, toEnum, enumFromTo, cardinality, succ, fromEnum, pred) -import Data.Date as Date -import Data.Time as Time -import Data.Time.Duration as Duration -import Data.Interval as Interval -import Data.Interval.Duration.Iso (mkIsoDuration) import Data.Array as Array +import Data.Date as Date import Data.DateTime as DateTime -import Data.DateTime.Locale as Locale import Data.DateTime.Instant as Instant +import Data.DateTime.Locale as Locale +import Data.Either (Either(..), isRight) +import Data.Enum (class BoundedEnum, Cardinality, toEnum, enumFromTo, cardinality, succ, fromEnum, pred) import Data.Foldable (foldl, foldr, foldMap) +import Data.Interval as Interval +import Data.Interval.Duration.Iso as IsoDuration import Data.Maybe (Maybe(..), fromJust) +import Data.Monoid (mempty) +import Data.Newtype (over, unwrap) +import Data.NonEmpty (NonEmpty(..)) import Data.String (length) +import Data.Time as Time +import Data.Time.Duration as Duration import Data.Traversable (sequence, traverse) import Data.Tuple (Tuple(..), snd) -import Data.Monoid (mempty) -import Data.Newtype (over, unwrap) - import Math (floor) - -import Type.Proxy (Proxy(..)) import Test.Assert (ASSERT, assert) +import Type.Proxy (Proxy(..)) import Partial.Unsafe (unsafePartial) type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit @@ -36,13 +35,17 @@ main = do log "check Duration monoid" assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0) assert $ Interval.second 0.5 == Interval.millisecond 500.0 - assert $ Interval.week 1.0 == Interval.day 7.0 - assert $ mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing - assert $ mkIsoDuration (Interval.week 1.2 <> Interval.second 0.0) /= Nothing - assert $ mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing - assert $ mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing - assert $ mkIsoDuration (Interval.year 2.0 <> Interval.week (-1.0)) == Nothing - assert $ mkIsoDuration (mempty) == Nothing + assert $ IsoDuration.mkIsoDuration (Interval.week 1.2 <> Interval.week 1.2) + == IsoDuration.mkIsoDuration (Interval.week 2.4) + assert $ isRight $ IsoDuration.mkIsoDuration (Interval.day 1.2 <> mempty) + assert $ isRight $ IsoDuration.mkIsoDuration (Interval.day 1.2 <> Interval.second 0.0) + assert $ isRight $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day 1.0) + assert $ IsoDuration.mkIsoDuration (Interval.year 2.5 <> Interval.day 1.0) + == Left (NonEmpty (IsoDuration.InvalidFractionalUse Interval.Year) []) + assert $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day (-1.0)) + == Left (NonEmpty (IsoDuration.ContainsNegativeValue Interval.Day) []) + assert $ IsoDuration.mkIsoDuration (mempty) + == Left (NonEmpty IsoDuration.IsEmpty []) let epochDate = unsafePartial fromJust $ Date.canonicalDate <$> toEnum 1 From 08c4d820ad1332c31e36e98b78dc99fcaf8463fe Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 21:33:43 +0400 Subject: [PATCH 32/33] move checkWeekUsage up add tests This way InvalidWeekComponentUsage will be first if it is present in errors --- src/Data/Interval/Duration/Iso.purs | 5 +++-- test/Test/Main.purs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Data/Interval/Duration/Iso.purs b/src/Data/Interval/Duration/Iso.purs index c9b8293..edc6f8e 100644 --- a/src/Data/Interval/Duration/Iso.purs +++ b/src/Data/Interval/Duration/Iso.purs @@ -57,10 +57,11 @@ checkValidIsoDuration (Duration asMap) = check {asList, asMap} where asList = reverse (Map.toAscUnfoldable asMap) check = fold - [ checkEmptiness + [ checkWeekUsage + , checkEmptiness , checkFractionalUse , checkNegativeValues - , checkWeekUsage] + ] type CheckEnv = diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 4dafb23..504d238 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -42,6 +42,8 @@ main = do assert $ isRight $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day 1.0) assert $ IsoDuration.mkIsoDuration (Interval.year 2.5 <> Interval.day 1.0) == Left (NonEmpty (IsoDuration.InvalidFractionalUse Interval.Year) []) + log $ show $ IsoDuration.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) + == Left (NonEmpty IsoDuration.InvalidWeekComponentUsage [IsoDuration.InvalidFractionalUse Interval.Year]) assert $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day (-1.0)) == Left (NonEmpty (IsoDuration.ContainsNegativeValue Interval.Day) []) assert $ IsoDuration.mkIsoDuration (mempty) From 84d8b2c177e2431f9ecbbf40cab6a28da642d184 Mon Sep 17 00:00:00 2001 From: Irakli Safareli Date: Fri, 23 Jun 2017 22:15:32 +0400 Subject: [PATCH 33/33] use NonEmptyList instead of NonEmpty Array; add prettyError --- src/Data/Interval/Duration/Iso.purs | 39 ++++++++++++++++++----------- test/Test/Main.purs | 11 ++++---- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/src/Data/Interval/Duration/Iso.purs b/src/Data/Interval/Duration/Iso.purs index edc6f8e..10fe187 100644 --- a/src/Data/Interval/Duration/Iso.purs +++ b/src/Data/Interval/Duration/Iso.purs @@ -4,20 +4,22 @@ module Data.Interval.Duration.Iso , mkIsoDuration , Error(..) , Errors + , prettyError ) where import Prelude -import Data.Array (uncons) +import Control.Plus (empty) import Data.Either (Either(..)) import Data.Foldable (fold, foldMap) import Data.Interval.Duration (Duration(..), DurationComponent(..)) import Data.List (List(..), reverse, span, null) +import Data.List.NonEmpty (fromList) +import Data.List.Types (NonEmptyList) import Data.Map as Map import Data.Maybe (Maybe(..), isJust) import Data.Monoid.Additive (Additive(..)) import Data.Newtype (unwrap) -import Data.NonEmpty (NonEmpty(..)) import Data.Tuple (Tuple(..), snd) import Math as Math @@ -28,7 +30,7 @@ derive instance ordIsoDuration :: Ord IsoDuration instance showIsoDuration :: Show IsoDuration where show (IsoDuration d) = "(IsoDuration " <> show d <> ")" -type Errors = NonEmpty Array Error +type Errors = NonEmptyList Error data Error = IsEmpty @@ -44,15 +46,22 @@ instance showError :: Show Error where show (ContainsNegativeValue c) = "(ContainsNegativeValue " <> show c <> ")" show (InvalidFractionalUse c) = "(InvalidFractionalUse " <> show c <> ")" +prettyError :: Error -> String +prettyError (IsEmpty) = "Duration is empty (has no components)" +prettyError (InvalidWeekComponentUsage) = "Week component of Duration is used with other components" +prettyError (ContainsNegativeValue c) = "Component `" <> show c <> "` contains negative value" +prettyError (InvalidFractionalUse c) = "Invalid usage of Fractional value at component `" <> show c <> "`" + + unIsoDuration :: IsoDuration -> Duration unIsoDuration (IsoDuration a) = a mkIsoDuration :: Duration -> Either Errors IsoDuration -mkIsoDuration d = case uncons (checkValidIsoDuration d) of - Just {head, tail} -> Left (NonEmpty head tail) +mkIsoDuration d = case fromList (checkValidIsoDuration d) of + Just errs -> Left errs Nothing -> Right (IsoDuration d) -checkValidIsoDuration :: Duration -> Array Error +checkValidIsoDuration :: Duration -> List Error checkValidIsoDuration (Duration asMap) = check {asList, asMap} where asList = reverse (Map.toAscUnfoldable asMap) @@ -68,21 +77,21 @@ type CheckEnv = { asList :: List (Tuple DurationComponent Number) , asMap :: Map.Map DurationComponent Number} -checkWeekUsage :: CheckEnv -> Array Error +checkWeekUsage :: CheckEnv -> List Error checkWeekUsage {asMap} = if isJust (Map.lookup Week asMap) && Map.size asMap > 1 - then [InvalidWeekComponentUsage] else [] + then pure InvalidWeekComponentUsage else empty -checkEmptiness :: CheckEnv -> Array Error -checkEmptiness {asList} = if null asList then [IsEmpty] else [] +checkEmptiness :: CheckEnv -> List Error +checkEmptiness {asList} = if null asList then pure IsEmpty else empty -checkFractionalUse :: CheckEnv -> Array Error +checkFractionalUse :: CheckEnv -> List Error checkFractionalUse {asList} = case _.rest (span (snd >>> not isFractional) asList) of - Cons (Tuple c _) rest | checkRest rest -> [InvalidFractionalUse c] - _ -> [] + Cons (Tuple c _) rest | checkRest rest -> pure (InvalidFractionalUse c) + _ -> empty where isFractional a = Math.floor a /= a checkRest rest = unwrap (foldMap (snd >>> Math.abs >>> Additive) rest) > 0.0 -checkNegativeValues :: CheckEnv -> Array Error +checkNegativeValues :: CheckEnv -> List Error checkNegativeValues {asList} = flip foldMap asList \(Tuple c num) -> - if num >= 0.0 then [] else [ContainsNegativeValue c] + if num >= 0.0 then empty else pure (ContainsNegativeValue c) diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 504d238..35fbfb8 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -17,16 +17,15 @@ import Data.Interval.Duration.Iso as IsoDuration import Data.Maybe (Maybe(..), fromJust) import Data.Monoid (mempty) import Data.Newtype (over, unwrap) -import Data.NonEmpty (NonEmpty(..)) import Data.String (length) import Data.Time as Time import Data.Time.Duration as Duration import Data.Traversable (sequence, traverse) import Data.Tuple (Tuple(..), snd) import Math (floor) +import Partial.Unsafe (unsafePartial) import Test.Assert (ASSERT, assert) import Type.Proxy (Proxy(..)) -import Partial.Unsafe (unsafePartial) type Tests = Eff (console :: CONSOLE, assert :: ASSERT) Unit @@ -41,13 +40,13 @@ main = do assert $ isRight $ IsoDuration.mkIsoDuration (Interval.day 1.2 <> Interval.second 0.0) assert $ isRight $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day 1.0) assert $ IsoDuration.mkIsoDuration (Interval.year 2.5 <> Interval.day 1.0) - == Left (NonEmpty (IsoDuration.InvalidFractionalUse Interval.Year) []) + == Left (pure (IsoDuration.InvalidFractionalUse Interval.Year)) log $ show $ IsoDuration.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) - == Left (NonEmpty IsoDuration.InvalidWeekComponentUsage [IsoDuration.InvalidFractionalUse Interval.Year]) + == Left (pure IsoDuration.InvalidWeekComponentUsage <> pure (IsoDuration.InvalidFractionalUse Interval.Year)) assert $ IsoDuration.mkIsoDuration (Interval.year 2.0 <> Interval.day (-1.0)) - == Left (NonEmpty (IsoDuration.ContainsNegativeValue Interval.Day) []) + == Left (pure (IsoDuration.ContainsNegativeValue Interval.Day)) assert $ IsoDuration.mkIsoDuration (mempty) - == Left (NonEmpty IsoDuration.IsEmpty []) + == Left (pure IsoDuration.IsEmpty) let epochDate = unsafePartial fromJust $ Date.canonicalDate <$> toEnum 1