1{-# OPTIONS_GHC -fno-warn-orphans #-}
2module ProjectM36.DataTypes.Interval where
3import ProjectM36.AtomFunctionBody
5import ProjectM36.AtomType
6import ProjectM36.DataTypes.Primitive
7import ProjectM36.AtomFunctionError
8import qualified Data.HashSet as HS
9import qualified Data.Map as M
10import Control.Monad (when)
13type OpenInterval = Bool
15intervalSubType :: AtomType -> AtomType
16intervalSubType typ = if isIntervalAtomType typ then
18 ConstructedAtomType _ tvMap ->
19 fromMaybe err (M.lookup "a" tvMap)
24 err = error "intervalSubType on non-interval type"
27-- in lieu of typeclass support, we just hard-code the types which can be part of an interval
28supportsInterval :: AtomType -> Bool
29supportsInterval typ = case typ of
31 IntegerAtomType -> True
32 DoubleAtomType -> True
33 TextAtomType -> False -- just because it supports ordering, doesn't mean it makes sense in an interval
35 DateTimeAtomType -> True
36 ByteStringAtomType -> False
38 RelationAtomType _ -> False
39 ConstructedAtomType _ _ -> False --once we support an interval-style typeclass, we might enable this
40 TypeVariableType _ -> False
42supportsOrdering :: AtomType -> Bool
43supportsOrdering typ = case typ of
45 IntegerAtomType -> True
46 DoubleAtomType -> True
49 DateTimeAtomType -> True
50 ByteStringAtomType -> False
52 RelationAtomType _ -> False
53 ConstructedAtomType _ _ -> False --once we support an interval-style typeclass, we might enable this
54 TypeVariableType _ -> False
56atomCompare :: Atom -> Atom -> Either AtomFunctionError Ordering
57atomCompare a1 a2 = let aType = atomTypeForAtom a1
58 go a b = Right (compare a b)
59 typError = Left (AtomTypeDoesNotSupportOrderingError (prettyAtomType aType)) in
60 if atomTypeForAtom a1 /= atomTypeForAtom a2 then
61 Left AtomFunctionTypeMismatchError
62 else if not (supportsOrdering aType) then
66 (IntegerAtom a, IntegerAtom b) -> go a b
67 (IntAtom a, IntAtom b) -> go a b
68 (DoubleAtom a, DoubleAtom b) -> go a b
69 (TextAtom a, TextAtom b) -> go a b
70 (DayAtom a, DayAtom b) -> go a b
71 (DateTimeAtom a, DateTimeAtom b) -> go a b
74--check that interval is properly ordered and that the boundaries make sense
75createInterval :: Atom -> Atom -> OpenInterval -> OpenInterval -> Either AtomFunctionError Atom
76createInterval atom1 atom2 bopen eopen = do
77 cmp <- atomCompare atom1 atom2
79 GT -> Left InvalidIntervalOrderingError
80 EQ -> if bopen || eopen then
81 Left InvalidIntervalBoundariesError
85 where valid = ConstructedAtom "Interval" iType [atom1, atom2, BoolAtom bopen, BoolAtom eopen]
86 iType = intervalAtomType (atomTypeForAtom atom1)
88intervalAtomType :: AtomType -> AtomType
89intervalAtomType typ = ConstructedAtomType "Interval" (M.singleton "a" typ)
91intervalAtomFunctions :: AtomFunctions
92intervalAtomFunctions = HS.fromList [
93 AtomFunction { atomFuncName = "interval",
94 atomFuncType = [TypeVariableType "a",
98 intervalAtomType (TypeVariableType "a")],
99 atomFuncBody = compiledAtomFunctionBody $ \(atom1:atom2:BoolAtom bopen:BoolAtom eopen:_) -> do
100 let aType = atomTypeForAtom atom1
101 if supportsInterval aType then
102 createInterval atom1 atom2 bopen eopen
104 Left (AtomTypeDoesNotSupportIntervalError (prettyAtomType aType))
107 atomFuncName = "interval_overlaps",
108 atomFuncType = [intervalAtomType (TypeVariableType "a"),
109 intervalAtomType (TypeVariableType "a"),
111 atomFuncBody = compiledAtomFunctionBody $ \(i1@ConstructedAtom{}:i2@ConstructedAtom{}:_) ->
112 BoolAtom <$> intervalOverlaps i1 i2
115isIntervalAtomType :: AtomType -> Bool
116isIntervalAtomType (ConstructedAtomType nam tvMap) =
117 nam == "Interval" && M.keys tvMap == ["a"] && case M.lookup "a" tvMap of
119 Just subType -> supportsInterval subType || subType == TypeVariableType "a"
120isIntervalAtomType _ = False
122intervalOverlaps :: Atom -> Atom -> Either AtomFunctionError Bool
123intervalOverlaps (ConstructedAtom dCons1 typ1 [i1start,
125 BoolAtom i1startopen,
126 BoolAtom i1endopen]) (ConstructedAtom dCons2 typ2
129 BoolAtom i2startopen,
130 BoolAtom i2endopen]) = do
131 when (dCons1 /= "Interval" || dCons2 /= "Interval" || not (isIntervalAtomType typ1) || not (isIntervalAtomType typ2)) (Left AtomFunctionTypeMismatchError)
132 cmp1 <- atomCompare i1start i2end
133 cmp2 <- atomCompare i2start i1end
134 let startcmp = if i1startopen || i2endopen then oplt else oplte
135 endcmp = if i2startopen || i1endopen then oplt else oplte
136 oplte op = op == LT || op == EQ
138 pure (startcmp cmp1 && endcmp cmp2)
139intervalOverlaps _ _ = Left AtomFunctionTypeMismatchError
141intervalTypeConstructorMapping :: TypeConstructorMapping
142intervalTypeConstructorMapping = [(ADTypeConstructorDef "Interval" ["a"], [])]
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list