The Squared and Rate units types allow you to build up and work with
composite units in a fairly flexible way.
Represents a units type that is the square of some other units type; for
example, Meters is one units type (the units type of a Length) and Squared
Meters is another (the units type of an Area). This is useful because some
functions in this module (specifically product,
squared, and sqrt) "know" about the Squared type and
how to work with it.
Represents the units type of a rate or quotient such as a speed (Rate
Meters Seconds) or a pressure (Rate Newtons SquareMeters). As with Squared,
there are several functions that "know" about the Rate units type and how to
work with it - see Working with rates for details.
A generic zero value. This can be treated as either an Int or Float
quantity in any units type, similar to how Nothing can be treated as any kind
of Maybe type and [] can be treated as any kind of List.
Alias for positiveInfinity.
A generic positive infinity value.
A generic negative infinity value.
Check if one quantity is less than another. Note the argument order!
oneMeter =
Length.meters 1
Length.feet 1 |> Quantity.lessThan oneMeter
--> True
-- Same as:
Quantity.lessThan oneMeter (Length.feet 1)
--> True
List.filter (Quantity.lessThan oneMeter)
[ Length.feet 1
, Length.parsecs 1
, Length.yards 1
, Length.lightYears 1
]
--> [ Length.feet 1, Length.yards 1 ]Check if one quantity is greater than another. Note the argument order!
oneMeter =
Length.meters 1
Length.feet 1 |> Quantity.greaterThan oneMeter
--> False
-- Same as:
Quantity.greaterThan oneMeter (Length.feet 1)
--> False
List.filter (Quantity.greaterThan oneMeter)
[ Length.feet 1
, Length.parsecs 1
, Length.yards 1
, Length.lightYears 1
]
--> [ Length.parsecs 1, Length.lightYears 1 ]Compare two quantities, returning an Order
value indicating whether the first is less than, equal to or greater than the
second.
Quantity.compare (Duration.minutes 90) (Duration.hours 1)
--> GT
Quantity.compare (Duration.minutes 60) (Duration.hours 1)
--> EQCheck if two quantities are equal within a given absolute tolerance. The given tolerance must be greater than or equal to zero - if it is negative, then the result will always be false.
-- 3 feet is 91.44 centimeters or 0.9144 meters
Quantity.equalWithin (Length.centimeters 10)
(Length.meters 1)
(Length.feet 3)
--> True
Quantity.equalWithin (Length.centimeters 5)
(Length.meters 1)
(Length.feet 3)
--> FalseFind the maximum of two quantities.
Quantity.max (Duration.hours 2) (Duration.minutes 100)
--> Duration.hours 2Find the minimum of two quantities.
Quantity.min (Duration.hours 2) (Duration.minutes 100)
--> Duration.minutes 100Check if a quantity's underlying value is NaN (not-a-number).
Quantity.isNan (Quantity.sqrt (Area.squareMeters -4))
--> True
Quantity.isNan (Quantity.sqrt (Area.squareMeters 4))
--> FalseCheck if a quantity is positive or negative infinity.
Quantity.isInfinite
(Length.meters 1
|> Quantity.per (Duration.seconds 0)
)
--> True
Quantity.isInfinite Quantity.negativeInfinity
--> TrueNegate a quantity!
Quantity.negate (Length.millimeters 10)
--> Length.millimeters -10Add two quantities.
Length.meters 1 |> Quantity.plus (Length.centimeters 5)
--> Length.centimeters 105Subtract one quantity from another. Note the argument order!
fifteenMinutes =
Duration.minutes 15
Duration.hours 1 |> Quantity.minus fifteenMinutes
--> Duration.minutes 45
-- Same as:
Quantity.minus fifteenMinutes (Duration.hours 1)
--> Duration.minutes 45
List.map (Quantity.minus fifteenMinutes)
[ Duration.hours 1
, Duration.hours 2
, Duration.minutes 30
]
--> [ Duration.minutes 45
--> , Duration.minutes 105
--> , Duration.minutes 15
--> ]Multiply two quantities with the same units together, resulting in a
quantity in Squared units.
This works for any units type (which is useful when used with sqrt!)
but one special case is worth pointing out. The units type of an Area
is SquareMeters, which is a type alias for Squared Meters. This means that
the product of two Lengths does in fact give you an Area:
Quantity.product
(Length.meters 2)
(Length.centimeters 40)
--> Area.squareMeters 0.8
-- This is the definition of an acre, I kid you not 😈
Quantity.product (Length.feet 66) (Length.feet 660)
--> Area.acres 1Note that there are other forms of multiplication!
Find the ratio of two quantities with the same units.
Quantity.ratio (Length.miles 1) (Length.yards 1)
--> 1760Multiply a Quantity by a number.
Quantity.scaleBy 1.5 (Duration.hours 1)
--> Duration.minutes 90Note that there are other forms of multiplication!
Divide a Quantity by a Float.
Quantity.divideBy 2 (Duration.hours 1)
--> Duration.minutes 30Get the absolute value of a quantity.
Quantity.abs (Duration.milliseconds -10)
--> Duration.milliseconds 10Given a lower and upper bound, clamp a given quantity to within those bounds. Say you wanted to clamp an angle to be between +/-30 degrees:
lowerBound =
Angle.degrees -30
upperBound =
Angle.degrees 30
Quantity.clamp lowerBound upperBound (Angle.degrees 5)
--> Angle.degrees 5
-- One radian is approximately 57 degrees
Quantity.clamp lowerBound upperBound (Angle.radians 1)
--> Angle.degrees 30
Quantity.clamp lowerBound upperBound (Angle.turns -0.5)
--> Angle.degrees -30Square a quantity with some units, resulting in a new quantity in
Squared units:
Quantity.squared (Length.meters 5)
--> Area.squareMeters 25(See the documentation of product for an explanation of why a
squared Length does in fact give you an Area.)
Take a quantity in Squared units and return the square root of that
quantity in plain units:
Quantity.sqrt (Area.hectares 1)
--> Length.meters 100Getting fancier, you could write a 2D hypotenuse (magnitude) function that worked on any quantity type (length, speed, force...) as
hypotenuse :
Quantity Float units
-> Quantity Float units
-> Quantity Float units
hypotenuse x y =
Quantity.sqrt <|
Quantity.sum
[ Quantity.squared x
, Quantity.squared y
]This works because:
x and y arguments are both in unitsSquared unitsSquared unitssqrt on something in Squared units returns a value back in
unitsInt/Float conversionThese functions only really make sense for quantities in units like pixels,
cents or game tiles where an Int number of units is meaningful. For quantities
like Length or Duration, it doesn't really make sense to round to an Int
value since the underyling base unit is pretty arbitrary - should rounding a
Duration give you an Int number of seconds, milliseconds, or something else?
Round a Float-valued quantity to the nearest Int.
Quantity.round (Pixels.pixels 3.5)
--> Pixels.pixels 4Round a Float-valued quantity down to the nearest Int.
Quantity.floor (Pixels.pixels 2.9)
--> Pixels.pixels 2
Quantity.floor (Pixels.pixels -2.1)
--> Pixels.pixels -3Round a Float-valued quantity up to the nearest Int.
Quantity.ceiling (Pixels.pixels 1.2)
--> Pixels.pixels 2
Quantity.ceiling (Pixels.pixels -2.1)
--> Pixels.pixels -2Round a Float-valued quantity towards zero.
Quantity.truncate (Pixels.pixels -2.8)
--> Pixels.pixels -2Convert a Quantity Int units to a Quantity Float units with the same
value. Useful when you have an Int-valued quantity and want to divide it by
something, multiply it by a fractional value etc.
These functions act just like the corresponding functions in the built-in List
module. They're necessary because the built-in List.sum only supports List
Int and List Float, and minimum/maximum/sort only support built-in
comparable types like Int, Float, String and tuples.
Find the sum of a list of quanties.
Quantity.sum
[ Length.meters 1
, Length.centimeters 2
, Length.millimeters 3
]
--> Length.meters 1.023
Quantity.sum []
--> Quantity.zeroFind the minimum value in a list of quantities. Returns Nothing if the
list is empty.
Quantity.minimum
[ Mass.kilograms 1
, Mass.pounds 2
, Mass.tonnes 3
]
--> Just (Mass.pounds 2)Find the maximum value in a list of quantities. Returns Nothing if the
list is empty.
Quantity.maximum
[ Mass.kilograms 1
, Mass.pounds 2
, Mass.tonnes 3
]
--> Just (Mass.tonnes 3)Sort a list of quantities.
Quantity.sort
[ Mass.kilograms 1
, Mass.pounds 2
, Mass.tonnes 3
]
--> [ Mass.pounds 2
--> , Mass.kilograms 1
--> , Mass.tonnes 3
--> ]Construct a rate of change by dividing a dependent quantity (numerator) by an independent quantity (denominator):
distance =
Length.miles 1
time =
Duration.minutes 1
speed =
distance |> Quantity.per time
speed |> Speed.inMilesPerHour
--> 60Note that we could directly use our rate of change value as a Speed! That is
because many built-in quantity types are defined as rates of change, for
example:
Speed is Length per DurationAcceleration is Speed per DurationPressure is Force per AreaPower is Energy per DurationForce is Energy per LengthCurrent is Charge per DurationVoltage is Power per CurrentResistance is Voltage per CurrentMultiply a rate of change by an independent quantity (the denominator in the rate) to get a total value:
-- Pressure is force per area
pressure =
Pressure.kilopascals 10
area =
Area.squareMeters 3
pressure |> Quantity.times area
--> Force.newtons 30000Note that there are other forms of multiplication!
Same as times but with the argument order flipped, which may read better
in some cases:
Duration.minutes 30
|> Quantity.at
(Speed.kilometersPerHour 100)
--> Length.kilometers 50Can be useful to define conversion functions from one unit to another, since
if you define a rate then Quantity.at rate will give you a conversion
function:
pixelDensity : Quantity Float (Rate Pixels Meters)
pixelDensity =
Pixels.pixels 96 |> Quantity.per (Length.inches 1)
lengthToPixels : Length -> Quantity Float Pixels
lengthToPixels length =
Quantity.at pixelDensity length
lengthToPixels (Length.inches 3)
--> Pixels.pixels 288Eagle-eyed readers will note that using partial application you could also simply write
lengthToPixels =
Quantity.at pixelDensityGiven a rate and a dependent value, determine the necessary amount of the independent value:
Length.kilometers 75
|> Quantity.at_
(Speed.kilometersPerHour 100)
--> Duration.minutes 45Where times and at perform multiplication, at_ performs division - you
multiply a speed by a duration to get a distance, but you divide a distance by
a speed to get a duration.
Similar to at, at_ can be used to define an inverse conversion function:
pixelDensity : Quantity Float (Rate Pixels Meters)
pixelDensity =
Pixels.pixels 96 |> Quantity.per (Length.inches 1)
pixelsToLength : Quantity Float Pixels -> Length
pixelsToLength pixels =
Quantity.at_ pixelDensity pixels
pixelsToLength (Pixels.pixels 48)
--> Length.inches 0.5Find the inverse of a given rate. May be useful if you are using a rate to define a conversion, and want to convert the other way;
Quantity.at (Quantity.inverse rate)is equivalent to
Quantity.at_ rateIt is sometimes useful to be able to represent unitless quantities, especially
when working with generic code (in most other cases, it is likely simpler and
easier to just use Int or Float values directly). All the conversions in
this section simply wrap or unwrap a Float or Int value into a Quantity
value, and so should get compiled away entirely when using elm make
--optimize.
A special units type representing 'no units'. A Quantity Int Unitless
value is interchangeable with a simple Int, and a Quantity Float Unitless
value is interchangeable with a simple Float.
Convert a plain Int into a Quantity Int Unitless value.
Convert a Quantity Int Unitless value into a plain Int.
Convert a plain Float into a Quantity Float Unitless value.
Convert a Quantity Float Unitless value into a plain Float.
If you're looking for a function to convert a Quantity Int units to Quantity
Float units, check out toFloatQuantity.
A
Quantityis effectively anumber(anIntorFloat) tagged with aunitstype. So ais a
Floatnumber ofMetersand ais an
Intnumber ofPixels. When compiling withelm make --optimizetheQuantitywrapper type will be compiled away, so the runtime performance should be comparable to using a rawFloatorInt.