rampart-2.0.0.0: Determine how intervals relate to each other.
Safe HaskellSafe-Inferred
LanguageHaskell2010

Rampart

Description

This module provides types and functions for defining intervals and determining how they relate to each other. This can be useful to determine if an event happened during a certain time frame, or if two time frames overlap (and if so, how exactly they overlap).

There are many other packages on Hackage that deal with intervals, notably data-interval and intervals. You may prefer one of them for more general interval operations. This module is more focused on how intervals relate to each other.

This module was inspired by James F. Allen's report, Maintaining Knowledge About Temporal Intervals. It also uses terminology from that report. You should not need to read the report in order to understand this module, but if you want to read it you can find it here: https://hdl.handle.net/1802/10574.

Synopsis

Documentation

data Interval a Source #

This type represents an interval bounded by two values, the lesser and the greater. These values can be anything with an Ord instance: numbers, times, strings — you name it.

Use toInterval to construct an interval and fromInterval to deconstruct one. Use relate to determine how two intervals relate to each other.

Instances

Instances details
Eq a => Eq (Interval a) Source # 
Instance details

Defined in Rampart

Methods

(==) :: Interval a -> Interval a -> Bool #

(/=) :: Interval a -> Interval a -> Bool #

Show a => Show (Interval a) Source # 
Instance details

Defined in Rampart

Methods

showsPrec :: Int -> Interval a -> ShowS #

show :: Interval a -> String #

showList :: [Interval a] -> ShowS #

toInterval :: Ord a => (a, a) -> Interval a Source #

Converts a tuple into an Interval. Note that this requires an Ord constraint so that the Interval can be sorted on construction.

Use fromInterval to go in the other direction.

fromInterval :: Interval a -> (a, a) Source #

Converts an Interval into a tuple. Generally you can think of this as the inverse of toInterval. However the tuple returned by this function may be swapped compared to the one originally passed to toInterval.

fromInterval (toInterval (1, 2)) == (1, 2)
fromInterval (toInterval (2, 1)) == (1, 2)
fromInterval (toInterval (x, y)) == (min x y, max x y)

lesser :: Interval a -> a Source #

Gets the lesser value from an Interval.

lesser (toInterval (1, 2)) == 1
lesser (toInterval (2, 1)) == 1
lesser (toInterval (x, y)) == min x y

greater :: Interval a -> a Source #

Gets the greater value from an Interval.

greater (toInterval (1, 2)) == 2
greater (toInterval (2, 1)) == 2
greater (toInterval (x, y)) == max x y

isEmpty :: Eq a => Interval a -> Bool Source #

Returns True if the given Interval is empty, False otherwise. An Interval is empty if its lesser equals its greater.

isEmpty (toInterval (1, 1)) == True
isEmpty (toInterval (1, 2)) == False

See isNonEmpty for the opposite check.

isNonEmpty :: Eq a => Interval a -> Bool Source #

Returns True if the given Interval is non-empty, False otherwise. An Interval is non-empty if its lesser is not equal to its greater.

isNonEmpty (toInterval (1, 2)) == True
isNonEmpty (toInterval (1, 1)) == False

See isEmpty for the opposite check.

data Relation Source #

This type describes how two Intervals relate to each other. Each constructor represents one of the 13 possible relations. Taken together these relations are mutually exclusive and exhaustive.

Use relate to determine the relation between two Intervals.

The following image shows all 13 possible Interval relations. If for whatever reason you can't see the image, each constructor for this type has ASCII art showing the Interval relation.

Constructors

Before

Interval x is before Interval y.

greater x < lesser y
+---+
| x |
+---+
      +---+
      | y |
      +---+
Meets

Interval x meets Interval y.

isNonEmpty x &&
greater x == lesser y
+---+
| x |
+---+
    +---+
    | y |
    +---+
Overlaps

Interval x overlaps Interval y.

lesser x < lesser y &&
greater x > lesser y &&
greater x < greater y
+---+
| x |
+---+
  +---+
  | y |
  +---+
FinishedBy

Interval x is finished by Interval y.

isNonEmpty y &&
lesser x < lesser y &&
greater x == greater y
+-----+
|  x  |
+-----+
  +---+
  | y |
  +---+
Contains

Interval x contains Interval y.

lesser x < lesser y &&
greater x > greater y
+-------+
|   x   |
+-------+
  +---+
  | y |
  +---+
Starts

Interval x starts Interval y.

isNonEmpty x &&
lesser x == lesser y &&
greater x < greater y
+---+
| x |
+---+
+-----+
|  y  |
+-----+
Equal

Interval x is equal to Interval y.

lesser x == lesser y &&
greater x == greater y
+---+
| x |
+---+
+---+
| y |
+---+
StartedBy

Interval x is started by Interval y.

isNonEmpty y &&
lesser x == lesser y &&
greater x > greater y
+-----+
|  x  |
+-----+
+---+
| y |
+---+
During

Interval x is during Interval y.

lesser x > lesser y &&
greater x < greater y
  +---+
  | x |
  +---+
+-------+
|   y   |
+-------+
Finishes

Interval x finishes Interval y.

isNonEmpty x &&
lesser x > lesser y &&
greater x == greater y
  +---+
  | x |
  +---+
+-----+
|  y  |
+-----+
OverlappedBy

Interval x is overlapped by Interval y.

lesser x > lesser y &&
lesser x < greater y &&
greater x > greater y
  +---+
  | x |
  +---+
+---+
| y |
+---+
MetBy

Interval x is met by Interval y.

isNonEmpty y &&
lesser x == greater y
    +---+
    | x |
    +---+
+---+
| y |
+---+
After

Interval x is after Interval y.

lesser x > greater y
      +---+
      | x |
      +---+
+---+
| y |
+---+

Instances

Instances details
Eq Relation Source # 
Instance details

Defined in Rampart

Show Relation Source # 
Instance details

Defined in Rampart

relate :: Ord a => Interval a -> Interval a -> Relation Source #

Relates two Intervals. Calling relate x y tells you how Interval x relates to Interval y. Consult the Relation documentation for an explanation of all the possible results.

relate (toInterval (1, 2)) (toInterval (3, 7)) == Before
relate (toInterval (2, 3)) (toInterval (3, 7)) == Meets
relate (toInterval (2, 4)) (toInterval (3, 7)) == Overlaps
relate (toInterval (2, 7)) (toInterval (3, 7)) == FinishedBy
relate (toInterval (2, 8)) (toInterval (3, 7)) == Contains
relate (toInterval (3, 4)) (toInterval (3, 7)) == Starts
relate (toInterval (3, 7)) (toInterval (3, 7)) == Equal
relate (toInterval (3, 8)) (toInterval (3, 7)) == StartedBy
relate (toInterval (4, 6)) (toInterval (3, 7)) == During
relate (toInterval (6, 7)) (toInterval (3, 7)) == Finishes
relate (toInterval (6, 8)) (toInterval (3, 7)) == OverlappedBy
relate (toInterval (7, 8)) (toInterval (3, 7)) == MetBy
relate (toInterval (8, 9)) (toInterval (3, 7)) == After

Note that relating an empty interval with a non-empty interval may be surprising when the intervals share an endpoint.

>>> relate (toInterval (3, 3)) (toInterval (3, 7)) == Overlaps
>>> relate (toInterval (7, 7)) (toInterval (3, 7)) == OverlappedBy
>>> relate (toInterval (3, 7)) (toInterval (3, 3)) == OverlappedBy
>>> relate (toInterval (3, 7)) (toInterval (7, 7)) == Overlaps

invert :: Relation -> Relation Source #

Inverts a Relation. Every Relation has an inverse.

invert Before       == After
invert After        == Before
invert Meets        == MetBy
invert MetBy        == Meets
invert Overlaps     == OverlappedBy
invert OverlappedBy == Overlaps
invert Starts       == StartedBy
invert StartedBy    == Starts
invert Finishes     == FinishedBy
invert FinishedBy   == Finishes
invert Contains     == During
invert During       == Contains
invert Equal        == Equal

Inverting a Relation twice will return the original Relation.

invert (invert r) == r

Inverting a Relation is like swapping the arguments to relate.

invert (relate x y) == relate y x