Skip to content

Commit 0ceb8eb

Browse files
committed
add IsoDuration; use Map instead of List Tuple
1 parent 0a7b628 commit 0ceb8eb

File tree

3 files changed

+58
-29
lines changed

3 files changed

+58
-29
lines changed

bower.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"purescript-functions": "^3.0.0",
2121
"purescript-generics": "^4.0.0",
2222
"purescript-integers": "^3.0.0",
23-
"purescript-math": "^2.0.0"
23+
"purescript-math": "^2.0.0",
24+
"purescript-maps": "^3.0.0"
2425
},
2526
"devDependencies": {
2627
"purescript-assert": "^3.0.0",

src/Data/Interval/Interval.purs

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
-- TODO commiting this temporarly as depending on my fork of datetime is
2-
-- not possibel as this module is not updated to [email protected]
31
module Data.Interval
4-
( Duration
5-
, Interval(..)
2+
( Interval(..)
63
, RecurringInterval(..)
4+
, IsoDuration
5+
, unIsoDuration
6+
, mkIsoDuration
7+
, isValidIsoDuration
8+
, Duration
79
, year
810
, month
911
, week
@@ -15,15 +17,19 @@ module Data.Interval
1517
) where
1618

1719
import Prelude
18-
import Control.Extend (class Extend)
19-
import Data.Bifunctor (class Bifunctor, bimap)
20-
import Data.Foldable (class Foldable, foldrDefault, foldMapDefaultL)
20+
import Control.Extend (class Extend, (=>>))
21+
import Data.Foldable (class Foldable, fold, foldMap, foldrDefault, foldMapDefaultL)
2122
import Data.Bifoldable (class Bifoldable, bifoldrDefault, bifoldMapDefaultL)
22-
import Data.List (List(..), (:))
23-
import Data.Maybe (Maybe)
23+
import Data.Bifunctor (class Bifunctor, bimap)
24+
import Data.List ((:), reverse)
25+
import Data.Maybe (Maybe(..))
26+
import Data.Map as Map
2427
import Data.Monoid (class Monoid, mempty)
28+
import Data.Monoid.Conj (Conj(..))
29+
import Data.Monoid.Additive (Additive(..))
2530
import Data.Traversable (class Traversable, sequenceDefault)
26-
import Data.Tuple (Tuple(..))
31+
import Data.Tuple (Tuple(..), snd)
32+
import Math as Math
2733

2834

2935
data RecurringInterval d a = RecurringInterval (Maybe Int) (Interval d a)
@@ -79,30 +85,51 @@ instance extendInterval ∷ Extend (Interval d) where
7985
extend f (JustDuration d) = JustDuration d
8086

8187

82-
data Duration = Duration DurationIn
83-
type DurationIn = List (Tuple DurationComponent Number)
88+
mkIsoDuration Duration Maybe IsoDuration
89+
mkIsoDuration d | isValidIsoDuration d = Just $ IsoDuration d
90+
mkIsoDuration _ = Nothing
91+
92+
isFractional Number Boolean
93+
isFractional a = Math.floor a /= a
94+
95+
-- allow only last number to be fractional
96+
isValidIsoDuration Duration Boolean
97+
isValidIsoDuration (Duration m) = Map.toAscUnfoldable m
98+
# reverse
99+
=>> (validateFractionalUse >>> Conj)
100+
# fold
101+
# unConj
102+
where
103+
unConj (Conj a) = a
104+
validateFractionalUse = case _ of
105+
(Tuple _ n):as | isFractional n → foldMap (snd >>> Additive) as == mempty
106+
_ → true
107+
108+
unIsoDuration IsoDuration Duration
109+
unIsoDuration (IsoDuration a) = a
110+
111+
data IsoDuration = IsoDuration Duration
112+
derive instance eqIsoDurationEq IsoDuration
113+
instance showIsoDurationShow IsoDuration where
114+
show (IsoDuration d)= "(IsoDuration " <> show d <> ")"
115+
84116

117+
data Duration = Duration (Map.Map DurationComponent Number)
85118
-- TODO `day 1 == hours 24`
86119
derive instance eqDurationEq Duration
120+
87121
instance showDurationShow Duration where
88122
show (Duration d)= "(Duration " <> show d <> ")"
89123

90124
instance semigroupDurationSemigroup Duration where
91-
append (Duration a) (Duration b) = Duration (appendComponents a b)
125+
append (Duration a) (Duration b) = Duration $ Map.unionWith (+) a b
92126

93127
instance monoidDurationMonoid Duration where
94128
mempty = Duration mempty
95129

96-
appendComponents DurationIn DurationIn DurationIn
97-
appendComponents Nil x = x
98-
appendComponents x Nil = x
99-
appendComponents ass@(a:as) bss@(b:bs) = case a, b of
100-
Tuple aC aV, Tuple bC bV
101-
| aC > bC → a : appendComponents as bss
102-
| aC < bC → b : appendComponents ass bs
103-
| otherwise → Tuple aC (aV + bV) : appendComponents as bs
104-
105130
data DurationComponent = Seconds | Minutes | Hours | Day | Month | Year
131+
derive instance eqDurationComponentEq DurationComponent
132+
derive instance ordDurationComponentOrd DurationComponent
106133

107134
instance showDurationComponentShow DurationComponent where
108135
show Year = "Year"
@@ -112,9 +139,6 @@ instance showDurationComponent ∷ Show DurationComponent where
112139
show Minutes = "Minutes"
113140
show Seconds = "Seconds"
114141

115-
derive instance eqDurationComponentEq DurationComponent
116-
derive instance ordDurationComponentOrd DurationComponent
117-
118142

119143
week Number Duration
120144
week = durationFromComponent Day <<< (_ * 7.0)
@@ -140,6 +164,6 @@ seconds = durationFromComponent Seconds
140164
milliseconds Number Duration
141165
milliseconds = durationFromComponent Seconds <<< (_ / 1000.0)
142166

143-
durationFromComponent DurationComponent Number Duration
144-
durationFromComponent c 0.0 = mempty
145-
durationFromComponent c n = Duration $ pure $ Tuple c n
167+
durationFromComponent DurationComponent Number Duration
168+
-- durationFromComponent _ 0.0 = mempty
169+
durationFromComponent k v= Duration $ Map.singleton k v

test/Test/Main.purs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ main = do
3030
assert $ Interval.year 1.0 == mempty <> Interval.year 2.0 <> Interval.year 1.0 <> Interval.year (-2.0)
3131
assert $ Interval.seconds 0.5 == Interval.milliseconds 500.0
3232
assert $ Interval.week 1.0 == Interval.day 7.0
33+
assert $ Interval.mkIsoDuration (Interval.week 1.2 <> mempty) /= Nothing
34+
assert $ Interval.mkIsoDuration (Interval.week 1.2 <> Interval.seconds 0.0) /= Nothing
35+
assert $ Interval.mkIsoDuration (Interval.year 2.0 <> Interval.week 1.0) /= Nothing
36+
assert $ Interval.mkIsoDuration (Interval.year 2.5 <> Interval.week 1.0) == Nothing
3337
-- time --------------------------------------------------------------------
3438

3539
log "Check that Hour is a good BoundedEnum"

0 commit comments

Comments
 (0)