module SIunits:Numerical values with units enforced at run-time.sig
..end
SIunits
provides run-time unit checking and automatic unit conversion.
Read the overview for an introduction to the features of this library, and consult the descriptions of the operators for further details.
Unless you require a large number of custom units, you should only need to
open
SIunits.Ops
and SIunits.Common
in order to use this library.
module Unit:sig
..end
module Value:sig
..end
module Ops:sig
..end
module Common:sig
..end
The two important types provided by SIunits
are the unit definitions
(SIunits.Unit.t
) and values (SIunits.Value.t
) that associate a numerical quantity
with a particular set of units.
Defining units
Units can be defined as combinations (SIunits.Unit.d
) of the basic SI units
(SIunits.Unit.u
), or by taking the product (SIunits.Unit.mult
) or ratio (SIunits.Unit.div
) of
existing units:
let kph = Common.km %/ Common.hour in ...
Non-SI units can also be defined as scalar multiples of existing units.
For example, millimetres of mercury (mmHg) can be defined in terms of pascals,
which are defined in SIunits.Common
:
let mmHg = Unit.scale 133.322387415 Common.pascal in ...
Units such as (hour)-1 can be defined using (min)-1:
let per_min = Unit.(per [Minute]) in
(* 1 per hour = 1/60 per minute *)
let per_hour = Unit.scale (1.0 /. 60.0) per_min in ...
Manipulating numerical quantities
Numerical quantities can then be associated with units and scaled to other units (which must have compatible dimensions):
let speed1 = 60.0 %< Common.km /: (2.0 %< Common.hour)
and speed2 = 30.0 %< kph (* equivalent to the line above *) in
let m_per_s = speed1 %> Unit.(ratio [Metre] [Second]) in ...
let pressure = 110.0 %< Common.mmHg %> Common.kilo_pascal in ...
Numerical quantities can be added and subtracted if their units are compatible and can also be multiplied or divided:
let dist1 = 5.0 %< Common.km
and dist2 = 212.0 %< Common.metre in
let sum = dist1 +: dist2
and area = dist1 *: dist2 in
let sum_cm = sum %> Common.cm (* 521200.0 cm *)
and area_km2 = area %> (Common.km %* Common.km) (* 1.06 km^2 *)
in ...
Mutable quantities
Mutable values (of type Value.t ref
) can be updated and referenced with the
<-:
and !:
operators, respectively.
The update operator will retain the units of the reference's original value.
let x_in_m = ref (2.0 %< Common.metre) in
x_in_m <-: (1.9 %< Common.km);
!: x_in_m = 1900.0 (* evaluates to true *)
Invalid units
An exception is thrown when two values with incompatible units are combined, and when a value is converted into a set of incompatible units:
let a = 5.0 %< Common.metre
and b = 1.0 %< Common.min in
a +: b (* raises Value.Invalid_units (a, b, "+:") *)
let a = 5.0 %< Common.metre in
a %> Common.min (* raises Value.Invalid_conversion (a, units) *)
Temperature
Common
defines several temperature conversion functions.
Note that arithmetic operations are performed with respect to
degrees Kelvin and will not produce values consistent with arithmetic in
degrees Celsius or degrees Fahrenheit:
let t1 = from_celsius 30.0
and t2 = from_celsius 10.0 in
to_celsius (t1 +: t2) (* 313 degrees Celsius *)
This is because they do not have the same zero-point as degrees Kelvin. Arithmetic with non-SI units that have the same zero-point as the SI units (e.g., inches, mmHg) will work as expected.
Operators
Operators are defined in SIunits.Unit
and SIunits.Value
, and are collected in SIunits.Ops
for
convenience.
The convention is that operators beginning with %
are concerned with units
(specifically unit creation, unit equivalence and unit conversion); operators
ending with :
are concerned with values (specifically arithmetic operations
and unit/numerical equality); operators ending with :.
perform scalar
operations on values.
Mutable values (Value.t ref
) are manipulated with the !:
and <-:
operators, which respectively return and update the value.
Both operators retain the original units associated with the mutable value.
The <-:
operator raises Invalid_units (v1, v2, "<-:")
if the units of the
original and new values are incompatible.
The precedence and associativity of the operators are defined in the
OCaml manual.
All binary operators are left-associative and the order of precedence is as
per the standard arithmetic operators: !:
has the highest precedence,
followed by the unit operators and value multiplication and division, then the
value addition and subtraction operators, and finally <-:
and the equality
operators.
This is why unit conversion can be written as:
let pressure = 110.0 %< Common.mmHg %> Common.kilo_pascal in ...
But the product or ratio of two values must be written as:
let speed1 = 60.0 %< Common.km /: (2.0 %< Common.hour) in ...