Represents a finite, closed interval with a minimum and maximum value, for
example the interval from 3 to 5. An Interval Int
represents a range of
integers and an Interval Float
represents a range of floating-point values.
from : number -> number -> Interval number
Construct an interval containing the two given values (which can be provided in either order).
Interval.endpoints (Interval.from 2 5)
--> ( 2, 5 )
Interval.endpoints (Interval.from 5 2)
--> ( 2, 5 )
fromEndpoints : ( number, number ) -> Interval number
Construct an interval from its endpoints (the minimum and maximum values of the interval).
rgbRange =
Interval.fromEndpoints ( 0, 255 )
alphaRange =
Interval.fromEndpoints ( 0, 1 )
The two values should be given in order but will be swapped if necessary to ensure a valid interval is returned:
Interval.endpoints (Interval.fromEndpoints ( 3, 2 ))
--> ( 2, 3 )
singleton : number -> Interval number
Construct a zero-width interval containing a single value.
Interval.singleton 3
--> Interval.fromEndpoints ( 3, 3 )
union : Interval number -> Interval number -> Interval number
Construct an interval containing both of the given intervals.
firstInterval =
Interval.from 1 2
secondInterval =
Interval.from 3 6
Interval.union firstInterval secondInterval
--> Interval.from 1 6
(Note that this is not strictly speaking a 'union' in the precise mathematical sense, since the result will contain values that are in between the two given intervals and not actually in either of them if those two intervals do not overlap.)
intersection : Interval number -> Interval number -> Maybe (Interval number)
Attempt to construct an interval containing all the values common to both
given intervals. If the intervals do not intersect, returns Nothing
.
Interval.intersection
(Interval.from 1 3)
(Interval.from 2 5)
--> Just (Interval.from 2 3)
Interval.intersection
(Interval.from 1 3)
(Interval.from 4 7)
--> Nothing
If the two intervals just touch, a singleton interval will be returned:
Interval.intersection
(Interval.from 1 3)
(Interval.from 3 5)
--> Just (Interval.singleton 3)
These functions let you construct an Interval
containing one or more input
numbers.
hull : number -> List number -> Interval number
Find the interval containing one or more input values:
Interval.hull 5 [ 3, 2, 4 ]
--> Interval.from 2 5
Often ends up being used within a case
expression:
case values of
[] ->
-- some default behavior
first :: rest ->
let
interval =
Interval.hull first rest
in
-- normal behavior using 'interval'
See also hullN
.
hullN : List number -> Maybe (Interval number)
Attempt to construct an interval containing all N values in the given
list. If the list is empty, returns Nothing
. If you know you have at least one
value, you can use hull
instead.
Interval.hullN [ 2, 1, 3 ]
--> Just (Interval.from 1 3)
Interval.hullN [ -3 ]
--> Just (Interval.singleton -3)
Interval.hullN []
--> Nothing
hullOf : (a -> number) -> a -> List a -> Interval number
Like hull
, but lets you work on any kind of item as long as a
number can be extracted from it. For example, if you had
type alias Person =
{ name : String
, age : Float
}
then given some people you could find their range of ages as an Interval
using
Interval.hullOf .age
firstPerson
[ secondPerson
, thirdPerson
, fourthPerson
]
See also hullOfN
.
hullOfN : (a -> number) -> List a -> Maybe (Interval number)
Combination of hullOf
and hullN
.
hull3 : number -> number -> number -> Interval number
Construct an interval containing the three given values;
Interval.hull3 a b c
is equivalent to
Interval.hull a [ b, c ]
but is more efficient. (If you're looking for a hull2
function, from
should do what you want.)
These functions let you 'aggregate' one or more intervals into a single larger interval that contains all of them.
aggregate : Interval number -> List (Interval number) -> Interval number
Construct an interval containing one or more given intervals:
Interval.aggregate
(Interval.singleton 2)
[ Interval.singleton 4
, Interval.singleton 3
]
--> Interval.from 2 4
Works much like hull
. See also aggregateN
.
aggregateN : List (Interval number) -> Maybe (Interval number)
Attemp to construct an interval containing all of the intervals in the given
list. If the list is empty, returns Nothing
. If you know you have at least one
interval, you can use aggregate
instead.
aggregateOf : (a -> Interval number) -> a -> List a -> Interval number
Like aggregate
, but lets you work on any kind of item as
long as an interval can be generated from it (similar to hullOf
).
aggregateOfN : (a -> Interval number) -> List a -> Maybe (Interval number)
Combination of aggregateOf
and aggregateN
.
aggregate3 : Interval number -> Interval number -> Interval number -> Interval number
Special case of aggregate
for the case of three intervals;
Interval.aggregate3 first second third
is equivalent to
Interval.aggregate first [ second, third ]
but is more efficient. (If you're looking for an aggregate2
function,
union
should do what you want.)
endpoints : Interval number -> ( number, number )
Get the endpoints of an interval (its minimum and maximum values) as a tuple. The first value will always be less than or equal to the second.
( minValue, maxValue ) =
Interval.endpoints someInterval
For any interval,
Interval.endpoints interval
is equivalent to (but more efficient than)
( Interval.minValue interval
, Interval.maxValue interval
)
minValue : Interval number -> number
Get the minimum value of an interval.
Interval.minValue (Interval.from 1 3)
--> 1
maxValue : Interval number -> number
Get the maximum value of an interval.
Interval.maxValue (Interval.from 1 3)
--> 3
midpoint : Interval Basics.Float -> Basics.Float
Get the midpoint of an interval.
Interval.midpoint (Interval.from 1 4)
--> 2.5
width : Interval number -> number
Get the width of an interval.
Interval.width (Interval.from 1 5)
--> 4
contains : number -> Interval number -> Basics.Bool
Check if an interval contains a given value.
Interval.contains 0 (Interval.from -1 3)
--> True
Interval.contains 5 (Interval.from -1 3)
--> False
The minimum and maximum values of an interval are considered to be contained in the interval:
Interval.contains 3 (Interval.from -1 3)
--> True
isContainedIn : Interval number -> Interval number -> Basics.Bool
Check if the second interval is fully contained in the first.
Interval.from -5 5
|> Interval.isContainedIn (Interval.from 0 10)
--> False
Interval.from -5 5
|> Interval.isContainedIn (Interval.from -10 10)
--> True
Be careful with the argument order! If not using the |>
operator, the second
example would be written as:
Interval.isContainedIn (Interval.from -10 10)
(Interval.from -5 5)
--> True
intersects : Interval number -> Interval number -> Basics.Bool
Check if two intervals touch or overlap (have any values in common).
Interval.from -5 5
|> Interval.intersects (Interval.from 0 10)
--> True
Interval.from -5 5
|> Interval.intersects (Interval.from 10 20)
--> False
Intervals that just touch each other are considered to intersect (this is
consistent with intersection
which will return a zero-width interval for the
intersection of two just-touching intervals):
Interval.from -5 5
|> Interval.intersects (Interval.from 5 10)
--> True
isSingleton : Interval number -> Basics.Bool
Check if the interval is a singleton (the minimum and maximum values are the same).
Interval.isSingleton (Interval.from 2 2)
--> True
Interval.isSingleton (Interval.from 2 3)
--> False
interpolate : Interval Basics.Float -> Basics.Float -> Basics.Float
Interpolate between an interval's endpoints based on a parameter value that will generally be between 0.0 and 1.0. A value of 0.0 corresponds to the minimum value of the interval, a value of 0.5 corresponds to its midpoint and a value of 1.0 corresponds to its maximum value:
Interval.interpolate (Interval.from 1 5) 0
--> 1
Interval.interpolate (Interval.from 1 5) 0.75
--> 4
Values less than 0.0 or greater than 1.0 can be used to extrapolate:
Interval.interpolate (Interval.from 1 5) 1.5
--> 7
Note that because of how Interval.from
works, the interpolation is in
fact from the minimum value to the maximum, not "from the first
Interval.from
argument to the second":
Interval.interpolate (Interval.from 0 10) 0.2
--> 2
Interval.interpolate (Interval.from 10 0) 0.2
--> 2 -- not 8!
If you want the interpolate from one number down to another, you can use
Float.Extra.interpolateFrom
from the elm-float-extra
package.
interpolationParameter : Interval Basics.Float -> Basics.Float -> Basics.Float
Given an interval and a given value, determine the corresponding
interpolation parameter (the parameter that you would pass to interpolate
to get the given value):
Interval.interpolationParameter
(Interval.from 10 15)
12
--> 0.4
The result will be between 0 and 1 if (and only if) the given value is within the given interval:
Interval.interpolationParameter
(Interval.from 10 15)
18
--> 1.6
Interval.interpolationParameter
(Interval.from 10 15)
9
--> -0.2
This is the inverse of interpolate
; for any non-zero-width interval
,
Interval.interpolationParameter interval value
|> Interval.interpolate interval
should be equal to the original value
(within numerical roundoff).
These functions let you do math with Interval
values, following the rules of
interval arithmetic.
negate : Interval number -> Interval number
Negate an interval. Note that this will flip the order of the endpoints.
Interval.negate (Interval.from 2 3)
--> Interval.from -3 -2
add : number -> Interval number -> Interval number
Add the given amount to an interval.
Interval.from -1 5 |> Interval.add 3
--> Interval.from 2 8
subtract : number -> Interval number -> Interval number
Subtract the given amount from an interval.
Interval.from -1 5 |> Interval.subtract 3
--> Interval.from -4 2
multiplyBy : number -> Interval number -> Interval number
Multiply an interval by a given value. Note that this will flip the order of the interval's endpoints if the given value is negative.
Interval.multiplyBy 5 (Interval.from 2 3)
--> Interval.from 10 15
Interval.multiplyBy -2 (Interval.from 2 3)
--> Interval.from -6 -4
divideBy : Basics.Float -> Interval Basics.Float -> Interval Basics.Float
Divide an interval by a given value. Note that this will flip the order of the interval's endpoints if the given value is negative.
Interval.divideBy 2 (Interval.from 2 3)
--> Interval.from 1 1.5
Interval.divideBy -2 (Interval.from 2 3)
--> Interval.from -1.5 -1
half : Interval Basics.Float -> Interval Basics.Float
Shorthand for multiplyBy 0.5
.
twice : Interval number -> Interval number
Shorthand for multiplyBy 2
.
plus : Interval number -> Interval number -> Interval number
Add two intervals together.
Interval.from 5 10
|> Interval.plus (Interval.from 2 3)
--> Interval.from 7 13
minus : Interval number -> Interval number -> Interval number
Subtract the first interval from the second. This means that minus
makes
the most sense when using |>
:
Interval.from 5 10
|> Interval.minus (Interval.from 2 3)
--> Interval.from 2 8
Without the pipe operator, the above would be written as:
Interval.minus (Interval.from 2 3)
(Interval.from 5 10)
--> Interval.from 2 8
times : Interval number -> Interval number -> Interval number
Multiply the two given intervals.
Interval.from 10 12
|> Interval.times
(Interval.from 5 6)
--> Interval.from 50 72
sin : Interval Basics.Float -> Interval Basics.Float
Get the image of sin(x) applied on the interval.
Interval.sin (Interval.from 0 (degrees 45))
--> Interval.from 0 0.7071
Interval.sin (Interval.from 0 pi)
--> Interval.from 0 1
cos : Interval Basics.Float -> Interval Basics.Float
Get the image of cos(x) applied on the interval.
Interval.cos (Interval.from 0 (degrees 45))
--> Interval.from 0.7071 1
Interval.cos (Interval.from 0 pi)
--> Interval.from -1 1