{-# OPTIONS_GHC -fno-warn-orphans #-}
module ProjectM36.DataTypes.Interval where
import ProjectM36.AtomFunctionBody
import ProjectM36.Base
import ProjectM36.AtomType
import ProjectM36.DataTypes.Primitive
import ProjectM36.AtomFunctionError
import qualified Data.HashSet as HS
import qualified Data.Map as M
import Control.Monad (when)
import Data.Maybe
type OpenInterval = Bool
intervalSubType :: AtomType -> AtomType
intervalSubType :: AtomType -> AtomType
intervalSubType AtomType
typ = if AtomType -> Bool
isIntervalAtomType AtomType
typ then
case AtomType
typ of
ConstructedAtomType TypeConstructorName
_ TypeVarMap
tvMap ->
forall a. a -> Maybe a -> a
fromMaybe forall {a}. a
err (forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TypeConstructorName
"a" TypeVarMap
tvMap)
AtomType
_ -> forall {a}. a
err
else
forall {a}. a
err
where
err :: a
err = forall a. HasCallStack => [Char] -> a
error [Char]
"intervalSubType on non-interval type"
supportsInterval :: AtomType -> Bool
supportsInterval :: AtomType -> Bool
supportsInterval AtomType
typ = case AtomType
typ of
AtomType
IntAtomType -> Bool
True
AtomType
IntegerAtomType -> Bool
True
AtomType
ScientificAtomType -> Bool
True
AtomType
DoubleAtomType -> Bool
True
AtomType
TextAtomType -> Bool
False
AtomType
DayAtomType -> Bool
True
AtomType
DateTimeAtomType -> Bool
True
AtomType
ByteStringAtomType -> Bool
False
AtomType
BoolAtomType -> Bool
False
AtomType
UUIDAtomType -> Bool
False
RelationAtomType Attributes
_ -> Bool
False
ConstructedAtomType TypeConstructorName
_ TypeVarMap
_ -> Bool
False
AtomType
RelationalExprAtomType -> Bool
False
SubrelationFoldAtomType{} -> Bool
False
TypeVariableType TypeConstructorName
_ -> Bool
False
supportsOrdering :: AtomType -> Bool
supportsOrdering :: AtomType -> Bool
supportsOrdering AtomType
typ = case AtomType
typ of
AtomType
IntAtomType -> Bool
True
AtomType
IntegerAtomType -> Bool
True
AtomType
ScientificAtomType -> Bool
True
AtomType
DoubleAtomType -> Bool
True
AtomType
TextAtomType -> Bool
True
AtomType
DayAtomType -> Bool
True
AtomType
DateTimeAtomType -> Bool
True
AtomType
ByteStringAtomType -> Bool
False
AtomType
BoolAtomType -> Bool
False
AtomType
UUIDAtomType -> Bool
False
RelationAtomType Attributes
_ -> Bool
False
AtomType
RelationalExprAtomType -> Bool
False
SubrelationFoldAtomType{} -> Bool
False
ConstructedAtomType TypeConstructorName
_ TypeVarMap
_ -> Bool
False
TypeVariableType TypeConstructorName
_ -> Bool
False
atomCompare :: Atom -> Atom -> Either AtomFunctionError Ordering
atomCompare :: Atom -> Atom -> Either AtomFunctionError Ordering
atomCompare Atom
a1 Atom
a2 = let aType :: AtomType
aType = Atom -> AtomType
atomTypeForAtom Atom
a1
go :: a -> a -> Either a Ordering
go a
a a
b = forall a b. b -> Either a b
Right (forall a. Ord a => a -> a -> Ordering
compare a
a a
b)
typError :: Either AtomFunctionError b
typError = forall a b. a -> Either a b
Left (TypeConstructorName -> AtomFunctionError
AtomTypeDoesNotSupportOrderingError (AtomType -> TypeConstructorName
prettyAtomType AtomType
aType)) in
if Atom -> AtomType
atomTypeForAtom Atom
a1 forall a. Eq a => a -> a -> Bool
/= Atom -> AtomType
atomTypeForAtom Atom
a2 then
forall a b. a -> Either a b
Left AtomFunctionError
AtomFunctionTypeMismatchError
else if Bool -> Bool
not (AtomType -> Bool
supportsOrdering AtomType
aType) then
forall {b}. Either AtomFunctionError b
typError
else
case (Atom
a1, Atom
a2) of
(IntegerAtom Integer
a, IntegerAtom Integer
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go Integer
a Integer
b
(IntAtom Int
a, IntAtom Int
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go Int
a Int
b
(DoubleAtom Double
a, DoubleAtom Double
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go Double
a Double
b
(TextAtom TypeConstructorName
a, TextAtom TypeConstructorName
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go TypeConstructorName
a TypeConstructorName
b
(DayAtom Day
a, DayAtom Day
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go Day
a Day
b
(DateTimeAtom UTCTime
a, DateTimeAtom UTCTime
b) -> forall {a} {a}. Ord a => a -> a -> Either a Ordering
go UTCTime
a UTCTime
b
(Atom, Atom)
_ -> forall {b}. Either AtomFunctionError b
typError
createInterval :: Atom -> Atom -> OpenInterval -> OpenInterval -> Either AtomFunctionError Atom
createInterval :: Atom -> Atom -> Bool -> Bool -> Either AtomFunctionError Atom
createInterval Atom
atom1 Atom
atom2 Bool
bopen Bool
eopen = do
Ordering
cmp <- Atom -> Atom -> Either AtomFunctionError Ordering
atomCompare Atom
atom1 Atom
atom2
case Ordering
cmp of
Ordering
GT -> forall a b. a -> Either a b
Left AtomFunctionError
InvalidIntervalOrderingError
Ordering
EQ -> if Bool
bopen Bool -> Bool -> Bool
|| Bool
eopen then
forall a b. a -> Either a b
Left AtomFunctionError
InvalidIntervalBoundariesError
else
forall a b. b -> Either a b
Right Atom
valid
Ordering
LT -> forall a b. b -> Either a b
Right Atom
valid
where valid :: Atom
valid = TypeConstructorName -> AtomType -> [Atom] -> Atom
ConstructedAtom TypeConstructorName
"Interval" AtomType
iType [Atom
atom1, Atom
atom2, Bool -> Atom
BoolAtom Bool
bopen, Bool -> Atom
BoolAtom Bool
eopen]
iType :: AtomType
iType = AtomType -> AtomType
intervalAtomType (Atom -> AtomType
atomTypeForAtom Atom
atom1)
intervalAtomType :: AtomType -> AtomType
intervalAtomType :: AtomType -> AtomType
intervalAtomType AtomType
typ = TypeConstructorName -> TypeVarMap -> AtomType
ConstructedAtomType TypeConstructorName
"Interval" (forall k a. k -> a -> Map k a
M.singleton TypeConstructorName
"a" AtomType
typ)
intervalAtomFunctions :: AtomFunctions
intervalAtomFunctions :: AtomFunctions
intervalAtomFunctions = forall a. (Eq a, Hashable a) => [a] -> HashSet a
HS.fromList [
Function { funcName :: TypeConstructorName
funcName = TypeConstructorName
"interval",
funcType :: [AtomType]
funcType = [TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a",
TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a",
AtomType
BoolAtomType,
AtomType
BoolAtomType,
AtomType -> AtomType
intervalAtomType (TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a")],
funcBody :: FunctionBody AtomFunctionBodyType
funcBody = AtomFunctionBodyType -> FunctionBody AtomFunctionBodyType
compiledAtomFunctionBody forall a b. (a -> b) -> a -> b
$
\case
(Atom
atom1:Atom
atom2:BoolAtom Bool
bopen:BoolAtom Bool
eopen:[Atom]
_) -> do
let aType :: AtomType
aType = Atom -> AtomType
atomTypeForAtom Atom
atom1
if AtomType -> Bool
supportsInterval AtomType
aType then
Atom -> Atom -> Bool -> Bool -> Either AtomFunctionError Atom
createInterval Atom
atom1 Atom
atom2 Bool
bopen Bool
eopen
else
forall a b. a -> Either a b
Left (TypeConstructorName -> AtomFunctionError
AtomTypeDoesNotSupportIntervalError (AtomType -> TypeConstructorName
prettyAtomType AtomType
aType))
[Atom]
_ -> forall a b. a -> Either a b
Left AtomFunctionError
AtomFunctionTypeMismatchError
},
Function {
funcName :: TypeConstructorName
funcName = TypeConstructorName
"interval_overlaps",
funcType :: [AtomType]
funcType = [AtomType -> AtomType
intervalAtomType (TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a"),
AtomType -> AtomType
intervalAtomType (TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a"),
AtomType
BoolAtomType],
funcBody :: FunctionBody AtomFunctionBodyType
funcBody = AtomFunctionBodyType -> FunctionBody AtomFunctionBodyType
compiledAtomFunctionBody forall a b. (a -> b) -> a -> b
$
\case
i1 :: Atom
i1@ConstructedAtom{}:i2 :: Atom
i2@ConstructedAtom{}:[Atom]
_ ->
Bool -> Atom
BoolAtom forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Atom -> Atom -> Either AtomFunctionError Bool
intervalOverlaps Atom
i1 Atom
i2
[Atom]
_ -> forall a b. a -> Either a b
Left AtomFunctionError
AtomFunctionTypeMismatchError
}]
isIntervalAtomType :: AtomType -> Bool
isIntervalAtomType :: AtomType -> Bool
isIntervalAtomType (ConstructedAtomType TypeConstructorName
nam TypeVarMap
tvMap) =
TypeConstructorName
nam forall a. Eq a => a -> a -> Bool
== TypeConstructorName
"Interval" Bool -> Bool -> Bool
&& forall k a. Map k a -> [k]
M.keys TypeVarMap
tvMap forall a. Eq a => a -> a -> Bool
== [TypeConstructorName
"a"] Bool -> Bool -> Bool
&& case forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup TypeConstructorName
"a" TypeVarMap
tvMap of
Maybe AtomType
Nothing -> Bool
False
Just AtomType
subType -> AtomType -> Bool
supportsInterval AtomType
subType Bool -> Bool -> Bool
|| AtomType
subType forall a. Eq a => a -> a -> Bool
== TypeConstructorName -> AtomType
TypeVariableType TypeConstructorName
"a"
isIntervalAtomType AtomType
_ = Bool
False
intervalOverlaps :: Atom -> Atom -> Either AtomFunctionError Bool
intervalOverlaps :: Atom -> Atom -> Either AtomFunctionError Bool
intervalOverlaps (ConstructedAtom TypeConstructorName
dCons1 AtomType
typ1 [Atom
i1start,
Atom
i1end,
BoolAtom Bool
i1startopen,
BoolAtom Bool
i1endopen]) (ConstructedAtom TypeConstructorName
dCons2 AtomType
typ2
[Atom
i2start,
Atom
i2end,
BoolAtom Bool
i2startopen,
BoolAtom Bool
i2endopen]) = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (TypeConstructorName
dCons1 forall a. Eq a => a -> a -> Bool
/= TypeConstructorName
"Interval" Bool -> Bool -> Bool
|| TypeConstructorName
dCons2 forall a. Eq a => a -> a -> Bool
/= TypeConstructorName
"Interval" Bool -> Bool -> Bool
|| Bool -> Bool
not (AtomType -> Bool
isIntervalAtomType AtomType
typ1) Bool -> Bool -> Bool
|| Bool -> Bool
not (AtomType -> Bool
isIntervalAtomType AtomType
typ2)) (forall a b. a -> Either a b
Left AtomFunctionError
AtomFunctionTypeMismatchError)
Ordering
cmp1 <- Atom -> Atom -> Either AtomFunctionError Ordering
atomCompare Atom
i1start Atom
i2end
Ordering
cmp2 <- Atom -> Atom -> Either AtomFunctionError Ordering
atomCompare Atom
i2start Atom
i1end
let startcmp :: Ordering -> Bool
startcmp = if Bool
i1startopen Bool -> Bool -> Bool
|| Bool
i2endopen then Ordering -> Bool
oplt else Ordering -> Bool
oplte
endcmp :: Ordering -> Bool
endcmp = if Bool
i2startopen Bool -> Bool -> Bool
|| Bool
i1endopen then Ordering -> Bool
oplt else Ordering -> Bool
oplte
oplte :: Ordering -> Bool
oplte Ordering
op = Ordering
op forall a. Eq a => a -> a -> Bool
== Ordering
LT Bool -> Bool -> Bool
|| Ordering
op forall a. Eq a => a -> a -> Bool
== Ordering
EQ
oplt :: Ordering -> Bool
oplt Ordering
op = Ordering
op forall a. Eq a => a -> a -> Bool
== Ordering
LT
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Ordering -> Bool
startcmp Ordering
cmp1 Bool -> Bool -> Bool
&& Ordering -> Bool
endcmp Ordering
cmp2)
intervalOverlaps Atom
_ Atom
_ = forall a b. a -> Either a b
Left AtomFunctionError
AtomFunctionTypeMismatchError
intervalTypeConstructorMapping :: TypeConstructorMapping
intervalTypeConstructorMapping :: TypeConstructorMapping
intervalTypeConstructorMapping = [(TypeConstructorName -> [TypeConstructorName] -> TypeConstructorDef
ADTypeConstructorDef TypeConstructorName
"Interval" [TypeConstructorName
"a"], [])]