Safe Haskell | Safe-Inferred |
---|---|

Language | Haskell2010 |

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

- data Interval a
- toInterval :: Ord a => (a, a) -> Interval a
- fromInterval :: Interval a -> (a, a)
- lesser :: Interval a -> a
- greater :: Interval a -> a
- isEmpty :: Eq a => Interval a -> Bool
- isNonEmpty :: Eq a => Interval a -> Bool
- data Relation
- relate :: Ord a => Interval a -> Interval a -> Relation
- invert :: Relation -> Relation

# Documentation

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

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.

This type describes how two `Interval`

s 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 `Interval`

s.

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.

Before |
+---+ | x | +---+ +---+ | y | +---+ |

Meets |
+---+ | x | +---+ +---+ | y | +---+ |

Overlaps |
+---+ | x | +---+ +---+ | y | +---+ |

FinishedBy |
+-----+ | x | +-----+ +---+ | y | +---+ |

Contains |
+-------+ | x | +-------+ +---+ | y | +---+ |

Starts |
+---+ | x | +---+ +-----+ | y | +-----+ |

Equal |
+---+ | x | +---+ +---+ | y | +---+ |

StartedBy |
+-----+ | x | +-----+ +---+ | y | +---+ |

During |
+---+ | x | +---+ +-------+ | y | +-------+ |

Finishes |
+---+ | x | +---+ +-----+ | y | +-----+ |

OverlappedBy |
+---+ | x | +---+ +---+ | y | +---+ |

MetBy |
+---+ | x | +---+ +---+ | y | +---+ |

After |
+---+ | x | +---+ +---+ | y | +---+ |

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

Relates two `Interval`

s. 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