This package is a port and extension of the framework elm-units.
Huge thanks to @ianmackenzie for creating the original package and writing much of
the original documentation.
Note: This framework is currently in alpha development.
To use this framework you include the package through the namespace
open Math.Units
Release notes for 2.0 are here.
Math.Units is useful if you want to store, pass around, convert between,
compare, or do arithmetic on:
- Durations (seconds, milliseconds, hours...)
- Angles (degrees, radians, turns...)
- Lengths (meters, feet, inches, miles, light years...)
- Temperatures (Celsius, Fahrenheit, kelvins)
- Pixels (whole or partial)
- Speeds (pixels per second, miles per hour...) or any other rate of change
-
Any of the other built-in quantity types: areas, accelerations, masses,
forces, pressures, currents, voltages...
-
Or even values in your own custom units, such as 'number of tiles' in a
tile-based game
It is aimed especially at engineering/scientific/technical applications but is
designed to be generic enough to work well for other fields such as games and
finance. The core of the package consists of a generic Quantity
type and
many concrete types such as Length
, Angle
, Duration
, Temperature
, and
Speed
, which you can use to add some nice type safety to data types and
function signatures:
type Camera =
{ fieldOfView: Angle
shutterSpeed: Duration
minimumOperatingTemperature: Temperature }
let canOperateAt (temperature: Temperature) (camera: Camera) : bool =
temperature
|> Temperature.greaterThan camera.minimumOperatingTemperature
You can construct values of these types from any units you want, using provided
functions such as:
Hint: hover over the function names to see the type values
Length.feet
Length.meters
Duration.seconds
Angle.degrees
Temperature.degreesFahrenheit
You can later convert back to plain numeric values, also in any units you want
(which do not have to be the same units used when initially constructing the
value!):
Length.inCentimeters
Length.inMiles
Duration.inHours
Angle.inRadians
Temperature.inDegreesCelsius
This means that (among other things!) you can use these functions to do simple
unit conversions:
Duration.hours 3. |> Duration.inSeconds
Length.feet 10. |> Length.inMeters
Speed.milesPerHour 60. |> Speed.inMetersPerSecond
Temperature.degreesCelsius 30.
|> Temperature.inDegreesFahrenheit
Additionally, types like Length
are actually type aliases of the form
Quantity number units
(Length
is Quantity Float Meters
, for example,
meaning that it is internally stored as a number of meters), and there are
many generic functions which let you work directly with any kind of Quantity
values:
Length.feet 3.
|> Quantity.lessThan (Length.meters 1.)
Duration.hours 2.
|> Quantity.plus (Duration.minutes 30.)
|> Duration.inSeconds
// Some functions can actually convert between units!
// Multiplying two Length values gives you an Area
Length.centimeters 60.
|> Quantity.times (Length.centimeters 80.)
Quantity.sort [ Angle.radians 1.
Angle.degrees 10.
Angle.turns 0.5 ]
[0.17453292519943295 Radians; 1 Radians; 3.141592653589793 Radians]
|
Ultimately, what this does is let you pass around and manipulate Length
,
Duration
or Temperature
etc. values without having to worry about units.
When you initially construct a Length
, you need to specify what units you're
using, but once that is done you can:
- Store the length inside a data structure
- Pass it around between different functions
- Compare it to other lengths
- Add and subtract it to other lengths
-
Multiply it by another length to get an area, or divide by a duration to
get a speed
...and much more, all without having to care about units at all. All
calculations will be done in an internally consistent way, and when you finally
need to actually display a value on screen or encode to JSON, you can extract
the final result in whatever units you want.
Assuming you have installed dotnet and
started a new project, you can install Math.Units
by running
dotnet add package Math.Units
in a command prompt inside your project directory.
To take code that currently uses raw float
values and convert it to using
Math.Units
types, there are three basic steps:
-
Wherever you store a
float
, such as in your model or in a message, switch
to storing a Duration
or Angle
or Temperature
etc. value instead.
-
Whenever you have a
Float
(from an external package, JSON decoder etc.),
use a function such as Duration.seconds
, Angle.degrees
or
Temperature.degreesFahrenheit
to turn it into a type-safe value.
-
Whenever you need a
float
(to pass to an external package, encode as
JSON etc.), use a function such as Duration.inMilliseconds
,
Angle.inRadians
or Temperature.inDegreesCelsius
to extract the value in
whatever units you want.
-
Where you do math with
Float
values, switch to using Quantity
functions
like Quantity.plus
or Quantity.greaterThan
. If this becomes impractical,
there are other approaches.
All values produced by this package (with the exception of Temperature
, which
is a bit of a special case) are actually values of type Quantity
, roughly
defined as...
type Quantity<'Units>(quantity: float) =
member this.Value = quantity
For example, Length
is defined as
type Meters = Meters
type Length = Quantity<Meters>
This means that a Length
is internally stored as a float
number of Meters
,
but the choice of internal units can mostly be treated as an implementation
detail.
Having a common Quantity
type means that it is possible to define generic
arithmetic and comparison operations that work on any kind of quantity; read on!
You can do basic math with Quantity
values:
// 6 feet 3 inches, converted to meters
Length.feet 6.
|> Quantity.plus (Length.inches 3.)
|> Length.inMeters
Duration.hours 1.
|> Quantity.minus (Duration.minutes 15.)
|> Duration.inMinutes
// pi radians plus 45 degrees is 5/8 of a full turn
Quantity.sum [ Angle.radians Math.PI
Angle.degrees 45. ]
|> Angle.inTurns
Quantity
values can be compared/sorted:
Length.meters 1.
|> Quantity.greaterThan (Length.feet 3.)
Quantity.compare (Length.meters 1.) (Length.feet 3.)
Quantity.max (Length.meters 1.) (Length.feet 3.)
Quantity.maximum [ Length.meters 1.
Length.feet 3. ]
Quantity.sort [ Length.meters 1.
Length.feet 3. ]
[0.9143999999999999 Meters; 1 Meters]
|
There are actually three different 'families' of multiplication and division
functions in the Quantity
module, used in different contexts:
-
multiplyBy
and divideBy
are used to multiply (scale) or divide a
Quantity
by a plain Int
or Float
, with twice
and half
for the common
cases of multiplying or dividing by 2
-
product
, times
, over
and over_
are used to work with quantities that
are products of other quantities:
- multiply a
Length
by another Length
to get an Area
- multiply an
Area
by a Length
to get a Volume
- multiply a
Mass
by an Acceleration
to get a Force
- divide a
Volume
by an Area
to get a Length
- divide a
Force
by a Mass
to get an Acceleration
-
rate
, per
, at
, at_
and for
are used to work with rates of change:
- divide
Length
by Duration
to get Speed
- multiply
Speed
by Duration
to get Length
- divide
Length
by Speed
to get Duration
-
And one bonus fourth function:
ratio
, used to divide two quantities with
the same units to get a plain Float
value
For example, to calculate the area of a triangle:
// Area of a triangle with base of 2 feet and
// height of 8 inches
let baseSize = Length.feet 2.
let height = Length.inches 8.
Quantity.half (Quantity.product baseSize height)
|> Area.inSquareInches
Comprehensive support is provided for working with rates of change:
// How fast are we going if we travel 30 meters in
// 2 seconds?
let speed =
Length.meters 30.
|> Quantity.per (Duration.seconds 2.)
// How far do we go if we travel for 2 minutes
// at that speed?
Duration.minutes 2. // duration
|> Quantity.at speed // length per duration
|> Length.inKilometers // gives us a length!
// How long will it take to travel 20 km
// if we're driving at 60 mph?
Length.kilometers 20.
|> Quantity.at_ (Speed.milesPerHour 60.)
|> Duration.inMinutes
// How fast is "a mile a minute", in kilometers per hour?
Length.miles 1.
|> Quantity.per (Duration.minutes 1.)
|> Speed.inKilometersPerHour
// Reverse engineer the speed of light from defined
// lengths/durations (the speed of light is 'one light
// year per year')
let speedOfLight =
Length.lightYears 1.
|> Quantity.per (Duration.julianYears 1.)
speedOfLight |> Speed.inMetersPerSecond
// One astronomical unit is the (average) distance from the
// Sun to the Earth. Roughly how long does it take light to
// reach the Earth from the Sun?
Length.astronomicalUnits 1.
|> Quantity.at_ speedOfLight
|> Duration.inMinutes
Note that the various functions above are not restricted to speed (length per
unit time) - any units work:
let pixelDensity =
Pixels.float 96.
|> Quantity.per (Length.inches 1.)
Length.centimeters 3. // length
|> Quantity.at pixelDensity // pixels per length
|> Pixels.toFloat // gives us pixels!
Note that several functions like Quantity.minus
and Quantity.lessThan
(and
their Temperature
equivalents) that mimic binary operators like -
and <
"take the second argument first"; for example,
Quantity.lessThan x y
means y < x
, not x < y
. This is done for a couple of reasons. First, so
that use with |>
works naturally; for example,
x |> Quantity.lessThan y
does mean x < y
. The 'reversed' argument order also means that things like
List.map (Quantity.minus x) [ a; b; c ]
will work as expected - it will result in
[ a - x, b - x, c - x ]
instead of
[ x - a, x - b, x - c ]
which is what you would get if Quantity.minus
took arguments in the 'normal'
order.
There are, however, several functions that take arguments in 'normal' order, for
example:
Quantity.difference
(compare to minus
)
Quantity.product
(compare to times
)
Quantity.rate
(compare to per
)
Quantity.ratio
Quantity.compare
In general the function names try to match how you would use them in English;
you would say "the difference of a
and b
" (and so Quantity.difference a b
)
but "a
minus b
" (and so a |> Quantity.minus b
).
Some calculations cannot be expressed using the built-in Quantity
functions.
Take kinetic energy E_k = 1/2 * m * v^2
, for example - the Math.Units
type
system is not sophisticated enough to work out the units properly. Instead,
you'd need to create a custom function like
let kineticEnergy (m: Mass) (v: Speed) : Energy =
Quantity.create (0.5 * m.Value * v.Value * v.Value)
In the implementation of kineticEnergy
, you're working with raw Float
values so you need to be careful to make sure the units actually do work out.
(The values will be in [SI units][https://en.wikipedia.org/wiki/International_System_of_Units]
- meters, seconds etc.) Once the function has been implemented, though, it
can be used in a completely type-safe way - callers can supply arguments
using whatever units they have, and extract results in whatever units they want:
[6]:
kineticEnergy (Mass.shortTons 1.5) (Speed.milesPerHour 60.)
|> Energy.inKilowattHours
Math.Units
defines many standard Unit Systems, but you can easily define your
own! See [CustomUnits][#CustomUnits] for an example.
The same quantity type can often be expressed in multiple different ways. Take
the Volume
type as an example. It is an alias for
Quantity<CubicMeters>
but expanding the CubicMeters
type alias, this is equivalent to
Quantity<Meters Cubed>
which expands further to
Quantity<Product<Product<Meters, Meters>, Meters>>
which could also be written as
Quantity<Product<Meters Squared, Meters>>
or even
Quantity<Product<SquareMeters, Meters>>
and you may see any one of these forms pop up in compiler error messages.
[Full API documentation][reference/math-units.html] is available.
This is a message from Ian Mackenzie but as the maintainer of this package I
believe in this mantra and will follow through with his wishes on giving
priority to issues regarding climate action.
I would like for the projects I work on to be as helpful as possible in
addressing the climate crisis. If
-
you are working on a project that helps address the climate crisis (clean
energy, public transit, reforestation, sustainable agriculture etc.) either as
an individual, as part of an non-profit organization or even as part of a
for-profit company, and
-
there is a new feature you would find helpful for that work (or a bug you need
fixed) in any of my open-source projects, then
please open a new issue,
describe briefly what you're working on and I will treat that issue as high
priority.
Yes please! One of the best ways to contribute is to add a module for a new
quantity type; I'll add a proper CONTRIBUTING.md at some point, but some
brief guidelines in the meantime:
-
Open a pull request by forking this repository, creating a new branch in
your fork, making all changes in that branch, then opening a pull request
from that branch.
-
Git commit messages should follow [the seven rules of a great Git commit
message][https://chris.beams.io/posts/git-commit/#seven-rules], although I'm not strict about the 50 or 72 character rules.
[elm-units BSD-3-Clause © Ian Mackenzie][https://github.com/ianmackenzie/elm-units/blob/master/LICENSE]
[Math.Units BSD-3-Clause © Thomas Waters][https://github.com/evelios/Math.Unitsrblob/master/LICENSE]
namespace System
type Math =
static member Abs: value: decimal -> decimal + 7 overloads
static member Acos: d: float -> float
static member Acosh: d: float -> float
static member Asin: d: float -> float
static member Asinh: d: float -> float
static member Atan: d: float -> float
static member Atan2: y: float * x: float -> float
static member Atanh: d: float -> float
static member BigMul: a: int * b: int -> int64 + 2 overloads
static member BitDecrement: x: float -> float
...
<summary>Provides constants and static methods for trigonometric, logarithmic, and other common mathematical functions.</summary>
namespace Math.Units
type Camera =
{
fieldOfView: Angle
shutterSpeed: Duration
minimumOperatingTemperature: Temperature
}
Camera.fieldOfView: Angle
Multiple items
module Angle
from Math.Units
<category>Module: Unit System</category>
<summary>
An <c>Angle</c> represents an angle in degrees, radians, or turns. It is stored
as a number of radians.
</summary>
<note>
Angles are sometimes measured in degrees, minutes, and seconds, where 1 minute =
1/60th of a degree and 1 second = 1/60th of a minute.
</note>
<example>
You can construct an angle from your unit scheme. All of the following are equivalent.
<code>
Angle.radians Math.PI
Angle.degrees 180.
Angle.turns 0.5
</code></example>
--------------------
type Angle = Quantity<Radians>
<category>Unit System</category>
Camera.shutterSpeed: Duration
Multiple items
module Duration
from Math.Units
<category>Module: Unit System</category>
A
<c>Duration</c>
refers to an elapsed time in seconds, milliseconds, hours etc.,
as opposed to a specific instant in time (which would generally be represented
by a
<see cref="System.DateTime" />
. value). It is stored as a number of seconds.
--------------------
type Duration = Quantity<Seconds>
<category>Unit System</category>
Camera.minimumOperatingTemperature: Temperature
Multiple items
module Temperature
from Math.Units
<category>Module: Unit System</category>
<summary>
Unlike other modules in <c>Math.Units</c>, this module contains two different
primary types:
<list type="bullet"><item><description><c>Temperature</c>, which is not actually a <c>Quantity</c> since temperatures don't
really act like normal quantities. For example, it doesn't make sense to
add two temperatures or find the ratio between them.
</description></item><item><description><c>TemperatureDelta</c>, which represents the difference between two temperatures. A <c>TemperatureDelta</c><i>is</i> a <c>Quantity</c> since it does make sense to add two deltas to get a net
delta, find the ratio between two deltas (one rise in temperature might be
twice as much as another rise in temperature), etc.
</description></item></list></summary>
<note>
Since a <c>Temperature</c> value is not a <c>Quantity</c>, this module exposes specialized
functions for doing the operations on <c>Temperature</c> values that <i>do</i> make sense,
such as comparing two temperatures or sorting a list of temperatures. It's also
possible to find the delta from one temperature to another using <c>Temperature.minus</c>,
and then add a <c>TemperatureDelta</c> to a <c>Temperature</c> using <c>Temperature.plus</c>.
</note>
--------------------
type Temperature =
interface IComparable
interface IComparable<Temperature>
new: kelvin: float -> Temperature
member Comparison: other: Temperature -> int
member Equals: other: Temperature -> bool + 1 overload
override GetHashCode: unit -> int
member LessThan: other: Temperature -> bool
override ToString: unit -> string
static member (+) : lhs: Temperature * rhs: TemperatureDelta -> Temperature + 1 overload
static member (-) : lhs: Temperature * rhs: Temperature -> TemperatureDelta
...
<category>Unit System</category>
--------------------
new: kelvin: float -> Temperature
val canOperateAt: temperature: Temperature -> camera: Camera -> bool
val temperature: Temperature
val camera: Camera
[<Struct>]
type bool = Boolean
<summary>An abbreviation for the CLI type <see cref="T:System.Boolean" />.</summary>
<category>Basic Types</category>
val greaterThan: rhs: Temperature -> lhs: Temperature -> bool
<category>Operators</category>
<summary>
This is meant to be used with pipe operators.
<code>
Temperature.inDegreesCelsius 30.
|> Temperature.greaterThan (Temperature.inDegreesCelsius 15.)
</code></summary>
Multiple items
module Length
from Math.Units
<category>Module: Unit System</category>
<summary>
A <c>Length</c> represents a length in meters, feet, centimeters, miles etc. It
is stored as a number of meters.
</summary>
--------------------
type Length = Quantity<Meters>
<category>Unit System</category>
val feet: l: float -> Length
<category>Imperial</category>
val meters: m: float -> Length
<category index="2">Metric</category>
val seconds: numSeconds: float -> Duration
<category index="1">Conversions</category>
<summary>
Construct a <c>Duration</c> from a given number of seconds.
</summary>
val degrees: d: float -> Angle
<category>Degrees</category>
Create an angle from a number of degrees.
val degreesFahrenheit: numDegreesFahrenheit: float -> Temperature
<category>Temperature Conversions</category>
Construct a temperature from a number of degrees Fahrenheit.
val inCentimeters: l: Length -> float
<category>Metric</category>
val inMiles: l: Length -> float
<category>Imperial</category>
val inHours: duration: Duration -> float
<category>Conversions</category>
<summary>
Convert a <c>Duration</c> to a value in hours.
</summary>
<example><code>
Duration.minutes 120 |> Duration.inHours
--> 2
</code></example>
val inRadians: r: Angle -> float
<category>Radians</category>
Get a
<c>float</c>
of the given angle in radians
val inDegreesCelsius: temperature: Temperature -> float
<category>Temperature Conversions</category>
Convert a temperature to a number of degrees Celsius.
val hours: numHours: float -> Duration
<category>Conversions</category>
<summary>
Construct a <c>Duration</c> from a given number of hours.
</summary>
<example><code>
Duration.hours 1
--> Duration.seconds 3600
</code></example>
val inSeconds: numSeconds: Duration -> float
<category>Conversions</category>
<summary>
Convert a <c>1</c> to a value in seconds.
</summary>
<example><code>
Duration.milliseconds 10 |> Duration.inSeconds
--> 0.01
</code></example>
val inMeters: l: Length -> float
<category>Metric</category>
Multiple items
module Speed
from Math.Units
<category>Module: Unit System</category>
<summary>
A <c>Speed</c> value represents a speed in meters per second, miles per hour etc.
It is stored as a number of meters per second.
</summary>
<note>
Since <c>MetersPerSecond</c> is defined as <c>Rate Meters Seconds</c> (length
per unit time), you can construct a <c>Speed</c> value using <c>Quantity.per</c>:
<code>
let speed =
length |> Quantity.per duration
</code>
You can also do rate-related calculations with <c>Speed</c> values to compute
<c>Length</c> or <c>Duration</c>:
<code>
let length =
speed |> Quantity.for duration
let alsoLength =
duration |> Quantity.at speed
let duration =
length |> Quantity.at_ speed
</code></note>
--------------------
type Speed = Quantity<MetersPerSecond>
<category>Unit System</category>
val milesPerHour: numMilesPerHour: float -> Speed
<category>Conversions</category>
Construct a speed from a number of miles per hour.
val inMetersPerSecond: numMetersPerSecond: Speed -> float
<category>Conversions</category>
Convert a speed to a number of meters per second.
val degreesCelsius: numDegreesCelsius: float -> Temperature
<category>Temperature Conversions</category>
Construct a temperature from a number of degrees Celsius.
val inDegreesFahrenheit: temperature: Temperature -> float
<category>Temperature Conversions</category>
Convert a temperature to a number of degrees Fahrenheit.
Multiple items
module Quantity
from Math.Units
<category>Module: Unit System</category>
--------------------
type Quantity<'Units> =
interface IComparable
interface IComparable<Quantity<'Units>>
new: quantity: float -> Quantity<'Units>
member Comparison: other: Quantity<'Units> -> int
member Equals: other: Quantity<'Units> -> bool + 1 overload
override GetHashCode: unit -> int
member LessThan: other: Quantity<'Units> -> bool
override ToString: unit -> string
static member (%) : q: Quantity<'Units> * modulus: Quantity<'Units> -> Quantity<'Units>
static member ( * ) : q: Quantity<'Units> * scale: float -> Quantity<'Units> + 2 overloads
...
<category>Unit System</category>
<summary>
A <c>Quantity</c> is effectively a <c>number</c> (an <c>Int</c> or <c>Float</c>) tagged with a
<c>units</c> type. So a
Quantity Float Meters
is a <c>Float</c> number of <c>Meters</c> and a
Quantity Int Pixels
is an <c>Int</c> number of <c>Pixels</c>. When compiling with <c>elm make --optimize</c> the
<c>Quantity</c> wrapper type will be compiled away, so the runtime performance should
be comparable to using a raw <c>Float</c> or <c>Int</c>.
</summary>
--------------------
new: quantity: float -> Quantity<'Units>
static member Quantity.lessThan: y: Quantity<'Units> -> x: Quantity<'Units> -> bool
static member Quantity.plus: y: Quantity<'Units> -> x: Quantity<'Units> -> Quantity<'Units>
val minutes: numMinutes: float -> Duration
<category>Conversions</category>
<summary>
Construct a <c>Duration</c> from a given number of minutes.
</summary>
<example><code>
Duration.minutes 3
--> Duration.seconds 180
</code></example>
val centimeters: l: float -> Length
<category>Metric</category>
static member Quantity.times: y: Quantity<'Units> -> x: Quantity<'Units> -> Quantity<Product<'Units,'Units>>
static member Quantity.sort: quantities: Quantity<'Units> list -> Quantity<'Units> list
val radians: r: float -> Angle
<category>Radians</category>
Create an angle from a number of radians.
val turns: numTurns: float -> Angle
<category>Turns</category>
Create an angle from a number of turns.
Multiple items
module Quantity
from Math.Units
<category>Module: Unit System</category>
--------------------
type Quantity<'Units> =
new: quantity: float -> Quantity<'Units>
member Value: float
--------------------
new: quantity: float -> Quantity<'Units>
val quantity: float
Multiple items
val float: value: 'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all
primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c>
with InvariantCulture settings. Otherwise the operation requires an appropriate
static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>
<example id="float-example"><code lang="fsharp"></code></example>
--------------------
[<Struct>]
type float = Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>
--------------------
type float<'Measure> =
float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure.
The unit of measure is erased in compiled code and when values of this type
are analyzed using reflection. The type is representationally equivalent to
<see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
val this: Quantity<'Units>
Multiple items
union case Meters.Meters: Meters
--------------------
type Meters = | Meters
Multiple items
module Length
from Math.Units
<category>Module: Unit System</category>
<summary>
A <c>Length</c> represents a length in meters, feet, centimeters, miles etc. It
is stored as a number of meters.
</summary>
--------------------
type Length = Quantity<Meters>
val inches: l: float -> Length
<category>Imperial</category>
static member Quantity.minus: y: Quantity<'Units> -> x: Quantity<'Units> -> Quantity<'Units>
val inMinutes: duration: Duration -> float
<category>Conversions</category>
<summary>
Convert a <c>Duration</c> to a value in minutes.
</summary>
<example><code>
Duration.seconds 90 |> Duration.inMinutes
--> 1.5
</code></example>
static member Quantity.sum: quantities: Quantity<'Units> list -> Quantity<'Units>
field Math.PI: float = 3.14159265359
val inTurns: angle: Angle -> float
<category>Turns</category>
Get a
<c>float</c>
of the given angle in turns.
static member Quantity.greaterThan: y: Quantity<'Units> -> x: Quantity<'Units> -> bool
static member Quantity.compare: x: Quantity<'Units> -> y: Quantity<'Units> -> int
static member Quantity.max: x: Quantity<'Units> -> y: Quantity<'Units> -> Quantity<'Units>
static member Quantity.maximum: quantities: Quantity<'Units> list -> Quantity<'Units> option
val baseSize: Length
val height: Length
static member Quantity.half: quantity: Quantity<'Units> -> Quantity<'Units>
static member Quantity.product: x: Quantity<'Units> -> y: Quantity<'Units> -> Quantity<Product<'Units,'Units>>
Multiple items
module Area
from Math.Units
<category>Module: Unit System</category>
<summary>
An <c>Area</c> represents an area in square meters, square feet, acres, hectares
etc. It is stored as a number of square meters.
Note that you can construct an <c>Area</c> value directly using the functions in this
module, but it also works to call <c>Quantity.squared</c> on a
<c>Length</c> or <c>Quantity.times</c> on a pair of <c>Length</c>s.
</summary>
<example>
The following are all equivalent:
<code>
Area.squareFeet 100
Quantity.squared (Length.feet 10)
Length.feet 25 |> Quantity.times (Length.feet 4)
</code></example>
--------------------
type Area = Quantity<SquareMeters>
<category>Unit System</category>
val inSquareInches: area: Area -> float
<category>Conversions</category>
Convert an area to a number of square inches.
val speed: Quantity<Rate<Meters,Seconds>>
static member Quantity.per: independentValue: Quantity<'Independent> -> dependentValue: Quantity<'Dependent> -> Quantity<Rate<'Dependent,'Independent>>
static member Quantity.at: rateOfChange: Quantity<Rate<'Dependent,'Independent>> -> independentValue: Quantity<'Independent> -> Quantity<'Dependent>
val inKilometers: l: Length -> float
<category>Metric</category>
val kilometers: l: float -> Length
<category>Metric</category>
static member Quantity.at_: rateOfChange: Quantity<Rate<'Dependent,'Independent>> -> dependentValue: Quantity<'Depenent> -> Quantity<'Independent>
val miles: l: float -> Length
<category>Imperial</category>
val inKilometersPerHour: speed: Speed -> float
<category>Conversions</category>
Convert a speed to a number of kilometers per hour.
val speedOfLight: Quantity<Rate<Meters,Seconds>>
val lightYears: l: float -> Length
<category>Astronomical</category>
val julianYears: numJulianYears: float -> Duration
<category>Conversions</category>
<summary>
Construct a <c>Duration</c> from a given number of
<see href="https://en.wikipedia.org/wiki/Julian_year_(astronomy)">Julian years</see>
A Julian year is defined as exactly 365.25 days, the average length of a year in
the historical Julian calendar. This is 10 minutes and 48 seconds longer than
a Gregorian year (365.2425 days), which is the average length of a year in the
modern Gregorian calendar, but the Julian year is a bit easier to remember and
reason about and has the virtue of being the 'year' value used in the definition
of a <see href="https://en.wikipedia.org/wiki/Light-year">light year</see>].
</summary>
<example><code>
Duration.julianYears 1
--> Duration.days 365.25
</code></example>
val astronomicalUnits: l: float -> Length
<category index="5">Astronomical</category>
val pixelDensity: Quantity<Rate<Pixel,Meters>>
Multiple items
module Pixels
from Math.Units
<category>Module: Unit System</category>
<summary>
Although most of the focus of <c>Math.Units</c> is on physical/scientific units,
it's often useful to be able to safely convert back and forth between (for
example) <c>Length</c> values in the real world and on-screen lengths in
pixels.
<para>
This module provides a standard <c>Pixels</c> units type and basic functions for
constructing/converting values of type <c>Quantity Int Pixels</c> or
<c>Quantity Float Pixels</c>, which allows you to do things like represent
conversions between real-world and on-screen lengths as rates of change.
This in turn means that all the normal <c>Quantity</c> functions can be
used to convert between pixels and other units, or even do type-safe math
directly on pixel values.
</para></summary>
--------------------
type Pixels = Quantity<Pixel>
<category>Unit System</category>
val float: numPixels: float -> Pixels
<category>Distance</category>
<summary>
Construct a quantity representing a floating-point number of on-screen
pixels:
<code>
let lineWeight =
Pixels.float 1.5
</code></summary>
val toFloat: numPixels: Pixels -> float
<category>Distance</category>
<summary>
Convert a floating-point number of pixels back into a plain <c>Float</c>:
</summary>
<example><code>
let pixelDensity =
Pixels.float 96 |> Quantity.per (Length.inches 1)
Length.centimeters 1
|> Quantity.at pixelDensity
|> Pixels.toFloat
--> 37.795275590551185
</code></example>
val x: Quantity<Unitless>
static member Quantity.unitless: value: float -> Quantity<Unitless>
val y: Quantity<Unitless>
val a: Quantity<Unitless>
val b: Quantity<Unitless>
val c: Quantity<Unitless>
Multiple items
module List
from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.list`1" />.</summary>
<namespacedoc><summary>Operations for collections such as lists, arrays, sets, maps and sequences. See also
<a href="https://docs.microsoft.com/dotnet/fsharp/language-reference/fsharp-collection-types">F# Collection Types</a> in the F# Language Guide.
</summary></namespacedoc>
--------------------
type List<'T> =
| op_Nil
| op_ColonColon of Head: 'T * Tail: 'T list
interface IReadOnlyList<'T>
interface IReadOnlyCollection<'T>
interface IEnumerable
interface IEnumerable<'T>
member GetReverseIndex: rank: int * offset: int -> int
member GetSlice: startIndex: int option * endIndex: int option -> 'T list
static member Cons: head: 'T * tail: 'T list -> 'T list
member Head: 'T
member IsEmpty: bool
member Item: index: int -> 'T with get
...
<summary>The type of immutable singly-linked lists.</summary>
<remarks>Use the constructors <c>[]</c> and <c>::</c> (infix) to create values of this type, or
the notation <c>[1;2;3]</c>. Use the values in the <c>List</c> module to manipulate
values of this type, or pattern match against the values directly.
</remarks>
<exclude />
val map: mapping: ('T -> 'U) -> list: 'T list -> 'U list
<summary>Builds a new collection whose elements are the results of applying the given function
to each of the elements of the collection.</summary>
<param name="mapping">The function to transform elements from the input list.</param>
<param name="list">The input list.</param>
<returns>The list of transformed elements.</returns>
<example id="map-1"><code lang="fsharp">
let inputs = [ "a"; "bbb"; "cc" ]
inputs |> List.map (fun x -> x.Length)
</code>
Evaluates to <c>[ 1; 3; 2 ]</c></example>
val kineticEnergy: m: Mass -> v: Speed -> Energy
val m: Mass
Multiple items
module Mass
from Math.Units
<category>Module: Unit System</category>
<summary>
A <c>Mass</c> represents a mass in kilograms, pounds, metric or imperial tons
etc. It is stored as a number of kilograms.
</summary>
--------------------
type Mass = Quantity<Kilograms>
<category>Unit System</category>
val v: Speed
Multiple items
module Energy
from Math.Units
<category>Module: Unit System</category>
<summary>
An <c>Energy</c> value represents an amount of energy (or work) in joules,
kilowatt hours etc. It is stored as a number of joules.
</summary>
<note><para>
Since <c>Joules</c> is defined as <c>Product<Newtons, Meters></c>,
you can compute energy directly as a product of force and distance:
</para><code>
Force.newtons 5 |> Quantity.times (Length.meters 4)
--> Energy.joules 20
</code></note>
--------------------
type Energy = Quantity<Joules>
<category>Unit System</category>
static member Quantity.create: value: float -> Quantity<'Units>
property Quantity.Value: float with get
val shortTons: numShortTons: float -> Mass
<category>Imperial</category>
<summary>
Construct a mass from a number of <a href="https://en.wikipedia.org/wiki/Short_ton">short tons</a>. This is the 'ton'
commonly used in the United States.
<code>
Mass.shortTons 1
--> Mass.pounds 2000
</code></summary>
val inKilowattHours: energy: Energy -> float
<category>Conversions</category>
Convert an energy value to a number of kilowatt hours.
type CubicMeters = Cubed<Meters>
<category>Unit</category>
type Cubed<'Units> = Product<'Units,Product<'Units,'Units>>
<category>Unit Relation</category>
<summary>
Represents a units type that is the cube of some other units type; for
example, <c>Meters</c> is one units type (the units type of a <c>Length</c>) and
<c>Cubed Meters</c> is another (the units type of an <c>Volume</c>). See the
<c>Quantity.cubed</c> and <c>Quantity.cbrt</c> functions for examples of
use.
This is a special case of the <c>Product</c> units type.
</summary>
Multiple items
union case Product.Product: 'Unit1 * 'Unit2 -> Product<'Unit1,'Unit2>
--------------------
type Product<'Unit1,'Unit2> = | Product of 'Unit1 * 'Unit2
<category>Unit Relation</category>
<summary>
Represents a units type that is the product of two other units types. This
is a more general form of <c>Squared</c> or <c>Cubed</c>. See
<see cref="M:Math.Units.Quantity.product">Quantity.product</see>,
<see cref="M:Math.Units.Quantity.times">Quantity.times</see>,
<see cref="M:Math.Units.Quantity.over">Quantity.over</see> and
<see cref="M:Math.Units.Quantity.over_">Quantity.over_</see> for how it can be used.
</summary>
type Squared<'Units> = Product<'Units,'Units>
<category>Unit Relation</category>
<summary>
Represents a units type that is the square of some other units type; for
example, <c>Meters</c> is one units type (the units type of a <c>Length</c>) and
<c>Squared Meters</c> is another (the units type of an <c>Area</c>). See the
<see cref="Math.Units.Quantity.squared">Quantity.squared</see> and [<c>sqrt</c>](#sqrt)
<see cref="Math.Units.Quantity.sqrt">Quantity.sqrt</see>
functions for examples of use. This is a special case of the <c>Product</c> units type.
</summary>
type SquareMeters = Squared<Meters>
<category>Unit</category>