dimensional-1.3: Statically checked physical dimensions, using Type Families and Data Kinds.

Numeric.Units.Dimensional

Description

# Summary

In this module we provide data types for performing arithmetic with physical quantities and units. Information about the physical dimensions of the quantities/units is embedded in their types and the validity of operations is verified by the type checker at compile time. The boxing and unboxing of numerical values as quantities is done by multiplication and division of units, of which an incomplete set is provided.

We limit ourselves to "Newtonian" physics. We do not attempt to accommodate relativistic physics in which e.g. addition of length and time would be valid.

As far as possible and/or practical the conventions and guidelines of NIST's "Guide for the Use of the International System of Units (SI)" [1] are followed. Occasionally we will reference specific sections from the guide and deviations will be explained.

## Disclaimer

Merely an engineer, the author doubtlessly uses a language and notation that makes mathematicians and physicist cringe. He does not mind constructive criticism (or pull requests).

The sets of functions and units defined herein are incomplete and reflect only the author's needs to date. Again, patches are welcome.

# Usage

## Preliminaries

This module requires GHC 8 or later. We utilize Data Kinds, TypeNats, Closed Type Families, etc. Clients of the module are generally not required to use these extensions.

Clients probably will want to use the NegativeLiterals extension.

## Examples

We have defined operators and units that allow us to define and work with physical quantities. A physical quantity is defined by multiplying a number with a unit (the type signature is optional).

v :: Velocity Prelude.Double
v = 90 *~ (kilo meter / hour)

It follows naturally that the numerical value of a quantity is obtained by division by a unit.

numval :: Prelude.Double
numval = v /~ (meter / second)

The notion of a quantity as the product of a numerical value and a unit is supported by 7.1 "Value and numerical value of a quantity" of [1]. While the above syntax is fairly natural it is unfortunate that it must violate a number of the guidelines in [1], in particular 9.3 "Spelling unit names with prefixes", 9.4 "Spelling unit names obtained by multiplication", 9.5 "Spelling unit names obtained by division".

As a more elaborate example of how to use the module we define a function for calculating the escape velocity of a celestial body [2].

escapeVelocity :: (Floating a) => Mass a -> Length a -> Velocity a
escapeVelocity m r = sqrt (two * g * m / r)
where
two = 2 *~ one
g = 6.6720e-11 *~ (newton * meter ^ pos2 / kilo gram ^ pos2)

For completeness we should also show an example of the error messages we will get from GHC when performing invalid arithmetic. In the best case GHC will be able to use the type synonyms we have defined in its error messages.

let x = 1 *~ meter + 1 *~ second

Couldn't match type 'Numeric.NumType.DK.Integers.Zero
with 'Numeric.NumType.DK.Integers.Pos1
Expected type: Unit 'Metric DLength a
Actual type: Unit 'Metric DTime a
In the second argument of (*~)', namely second'
In the second argument of (+)', namely 1 *~ second'

In other cases the error messages aren't very friendly.

let x = 1 *~ meter / (1 *~ second) + 1 *~ kilo gram

Couldn't match type 'Numeric.NumType.DK.Integers.Zero
with 'Numeric.NumType.DK.Integers.Neg1
Expected type: Quantity DMass a
Actual type: Dimensional
('DQuantity V.* 'DQuantity) (DLength / DTime) a
In the first argument of (+)', namely 1 *~ meter / (1 *~ second)'
In the expression: 1 *~ meter / (1 *~ second) + 1 *~ kilo gram
In an equation for x':
x = 1 *~ meter / (1 *~ second) + 1 *~ kilo gram

It is the author's experience that the usefulness of the compiler error messages is more often than not limited to pinpointing the location of errors.

# Notes

## Future work

While there is an insane amount of units in use around the world it is reasonable to provide those in relatively widespread use. Units outside of SI will most likely be added on an as-needed basis.

Additional physics models could be implemented. See [3] for ideas.

## Related work

Henning Thielemann numeric prelude has a physical units library, however, checking of dimensions is dynamic rather than static. Aaron Denney has created a toy example of statically checked physical dimensions covering only length and time. HaskellWiki has pointers [4] to these.

Also see Samuel Hoffstaetter's blog post [5] which uses techniques similar to this library.

Libraries with similar functionality exist for other programming languages and may serve as inspiration. The author has found the Java library JScience [6] and the Fortress programming language [7] particularly noteworthy.

Synopsis

# Types

Our primary objective is to define a data type that can be used to represent (while still differentiating between) units and quantities. There are two reasons for consolidating units and quantities in one data type. The first being to allow code reuse as they are largely subject to the same operations. The second being that it allows reuse of operators (and functions) between the two without resorting to occasionally cumbersome type classes.

The relationship between (the value of) a Quantity, its numerical value and its Unit is described in 7.1 "Value and numerical value of a quantity" of [1]. In short a Quantity is the product of a number and a Unit. We define the *~ operator as a convenient way to declare quantities as such a product.

data family Dimensional v :: Dimension -> Type -> Type Source #

A dimensional value, either a Quantity or a Unit, parameterized by its Dimension and representation.

Instances
 Vector Vector a => Vector Vector (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsbasicUnsafeFreeze :: PrimMonad m => Mutable Vector (PrimState m) (SQuantity s d a) -> m (Vector (SQuantity s d a)) #basicUnsafeThaw :: PrimMonad m => Vector (SQuantity s d a) -> m (Mutable Vector (PrimState m) (SQuantity s d a)) #basicLength :: Vector (SQuantity s d a) -> Int #basicUnsafeSlice :: Int -> Int -> Vector (SQuantity s d a) -> Vector (SQuantity s d a) #basicUnsafeIndexM :: Monad m => Vector (SQuantity s d a) -> Int -> m (SQuantity s d a) #basicUnsafeCopy :: PrimMonad m => Mutable Vector (PrimState m) (SQuantity s d a) -> Vector (SQuantity s d a) -> m () #elemseq :: Vector (SQuantity s d a) -> SQuantity s d a -> b -> b # MVector MVector a => MVector MVector (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsbasicLength :: MVector s0 (SQuantity s d a) -> Int #basicUnsafeSlice :: Int -> Int -> MVector s0 (SQuantity s d a) -> MVector s0 (SQuantity s d a) #basicOverlaps :: MVector s0 (SQuantity s d a) -> MVector s0 (SQuantity s d a) -> Bool #basicUnsafeNew :: PrimMonad m => Int -> m (MVector (PrimState m) (SQuantity s d a)) #basicInitialize :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> m () #basicUnsafeReplicate :: PrimMonad m => Int -> SQuantity s d a -> m (MVector (PrimState m) (SQuantity s d a)) #basicUnsafeRead :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> Int -> m (SQuantity s d a) #basicUnsafeWrite :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> Int -> SQuantity s d a -> m () #basicClear :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> m () #basicSet :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> SQuantity s d a -> m () #basicUnsafeCopy :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> MVector (PrimState m) (SQuantity s d a) -> m () #basicUnsafeMove :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> MVector (PrimState m) (SQuantity s d a) -> m () #basicUnsafeGrow :: PrimMonad m => MVector (PrimState m) (SQuantity s d a) -> Int -> m (MVector (PrimState m) (SQuantity s d a)) # Source # Instance detailsDefined in Numeric.Units.Dimensional.Dynamic MethodsdemotableOut :: Quantity d a -> AnyQuantity a Generic1 (Dimensional (DQuantity s) d :: Type -> Type) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typestype Rep1 (Dimensional (DQuantity s) d) :: k -> Type # Methodsfrom1 :: Dimensional (DQuantity s) d a -> Rep1 (Dimensional (DQuantity s) d) a #to1 :: Rep1 (Dimensional (DQuantity s) d) a -> Dimensional (DQuantity s) d a # Generic1 (Dimensional (DUnit m) d :: Type -> Type) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typestype Rep1 (Dimensional (DUnit m) d) :: k -> Type # Methodsfrom1 :: Dimensional (DUnit m) d a -> Rep1 (Dimensional (DUnit m) d) a #to1 :: Rep1 (Dimensional (DUnit m) d) a -> Dimensional (DUnit m) d a # KnownVariant v => Functor (Dimensional v d) Source # A Functor instance for Dimensional.Note that this instance is dubious, because it allows you to break the dimensional abstraction. See dmap for more information.Note that, while this instance overlaps with that given for Dimensionless, it is confluent with that instance.Note that this is an orphan instance. Instance detailsDefined in Numeric.Units.Dimensional.Functor Methodsfmap :: (a -> b) -> Dimensional v d a -> Dimensional v d b #(<$) :: a -> Dimensional v d b -> Dimensional v d a # Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsfmap :: (a -> b) -> SQuantity s DOne a -> SQuantity s DOne b #(<$) :: a -> SQuantity s DOne b -> SQuantity s DOne a # Eq1 (SQuantity s d) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsliftEq :: (a -> b -> Bool) -> SQuantity s d a -> SQuantity s d b -> Bool # Ord1 (SQuantity s d) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsliftCompare :: (a -> b -> Ordering) -> SQuantity s d a -> SQuantity s d b -> Ordering # NFData a => NFData (Quantity d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsrnf :: Quantity d a -> () # Bounded a => Bounded (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsminBound :: SQuantity s d a #maxBound :: SQuantity s d a # Eq a => Eq (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methods(==) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #(/=) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool # (Typeable s, Typeable d, Data a) => Data (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsgfoldl :: (forall d0 b. Data d0 => c (d0 -> b) -> d0 -> c b) -> (forall g. g -> c g) -> Dimensional (DQuantity s) d a -> c (Dimensional (DQuantity s) d a) #gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Dimensional (DQuantity s) d a) #toConstr :: Dimensional (DQuantity s) d a -> Constr #dataTypeOf :: Dimensional (DQuantity s) d a -> DataType #dataCast1 :: Typeable t => (forall d0. Data d0 => c (t d0)) -> Maybe (c (Dimensional (DQuantity s) d a)) #dataCast2 :: Typeable t => (forall d0 e. (Data d0, Data e) => c (t d0 e)) -> Maybe (c (Dimensional (DQuantity s) d a)) #gmapT :: (forall b. Data b => b -> b) -> Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a #gmapQl :: (r -> r' -> r) -> r -> (forall d0. Data d0 => d0 -> r') -> Dimensional (DQuantity s) d a -> r #gmapQr :: (r' -> r -> r) -> r -> (forall d0. Data d0 => d0 -> r') -> Dimensional (DQuantity s) d a -> r #gmapQ :: (forall d0. Data d0 => d0 -> u) -> Dimensional (DQuantity s) d a -> [u] #gmapQi :: Int -> (forall d0. Data d0 => d0 -> u) -> Dimensional (DQuantity s) d a -> u #gmapM :: Monad m => (forall d0. Data d0 => d0 -> m d0) -> Dimensional (DQuantity s) d a -> m (Dimensional (DQuantity s) d a) #gmapMp :: MonadPlus m => (forall d0. Data d0 => d0 -> m d0) -> Dimensional (DQuantity s) d a -> m (Dimensional (DQuantity s) d a) #gmapMo :: MonadPlus m => (forall d0. Data d0 => d0 -> m d0) -> Dimensional (DQuantity s) d a -> m (Dimensional (DQuantity s) d a) # Ord a => Ord (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodscompare :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Ordering #(<) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #(<=) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #(>) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #(>=) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #max :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a #min :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a # (KnownDimension d, KnownExactPi s, Show a, Real a) => Show (SQuantity s d a) Source # Uses non-breaking spaces between the value and the unit, and within the unit name. Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsshowsPrec :: Int -> SQuantity s d a -> ShowS #show :: SQuantity s d a -> String #showList :: [SQuantity s d a] -> ShowS # Show a => Show (Unit m d a) Source # Unit names are shown with non-breaking spaces. Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodsshowsPrec :: Int -> Unit m d a -> ShowS #show :: Unit m d a -> String #showList :: [Unit m d a] -> ShowS # Generic (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typestype Rep (Dimensional (DQuantity s) d a) :: Type -> Type # Methodsfrom :: Dimensional (DQuantity s) d a -> Rep (Dimensional (DQuantity s) d a) x #to :: Rep (Dimensional (DQuantity s) d a) x -> Dimensional (DQuantity s) d a # Generic (Dimensional (DUnit m) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typestype Rep (Dimensional (DUnit m) d a) :: Type -> Type # Methodsfrom :: Dimensional (DUnit m) d a -> Rep (Dimensional (DUnit m) d a) x #to :: Rep (Dimensional (DUnit m) d a) x -> Dimensional (DUnit m) d a # Num a => Semigroup (SQuantity s d a) Source # Quantitys of a given Dimension form a Semigroup under addition. Instance detailsDefined in Numeric.Units.Dimensional.Internal Methods(<>) :: SQuantity s d a -> SQuantity s d a -> SQuantity s d a #sconcat :: NonEmpty (SQuantity s d a) -> SQuantity s d a #stimes :: Integral b => b -> SQuantity s d a -> SQuantity s d a # Num a => Monoid (SQuantity s d a) Source # Quantitys of a given Dimension form a Monoid under addition. Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsmempty :: SQuantity s d a #mappend :: SQuantity s d a -> SQuantity s d a -> SQuantity s d a #mconcat :: [SQuantity s d a] -> SQuantity s d a # Storable a => Storable (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal MethodssizeOf :: SQuantity s d a -> Int #alignment :: SQuantity s d a -> Int #peekElemOff :: Ptr (SQuantity s d a) -> Int -> IO (SQuantity s d a) #pokeElemOff :: Ptr (SQuantity s d a) -> Int -> SQuantity s d a -> IO () #peekByteOff :: Ptr b -> Int -> IO (SQuantity s d a) #pokeByteOff :: Ptr b -> Int -> SQuantity s d a -> IO () #peek :: Ptr (SQuantity s d a) -> IO (SQuantity s d a) #poke :: Ptr (SQuantity s d a) -> SQuantity s d a -> IO () # AEq a => AEq (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methods(===) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool #(~==) :: Dimensional (DQuantity s) d a -> Dimensional (DQuantity s) d a -> Bool # Unbox a => Unbox (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal KnownDimension d => HasDimension (Dimensional v d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsdimension :: Dimensional v d a -> Dimension' Source # KnownDimension d => HasDynamicDimension (Dimensional v d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methods HasInterchangeName (Unit m d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methods data MVector v (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal data MVector v (SQuantity s d a) = MV_Quantity {unMVQ :: MVector v a} data Dimensional (DQuantity s) d a Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal data Dimensional (DQuantity s) d a = Quantity a data Dimensional (DUnit m) d a Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal data Dimensional (DUnit m) d a = Unit !(UnitName m) !ExactPi !a type Rep1 (Dimensional (DQuantity s) d :: Type -> Type) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal type Rep1 (Dimensional (DQuantity s) d :: Type -> Type) = D1 (MetaData "Dimensional" "Numeric.Units.Dimensional.Internal" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" True) (C1 (MetaCons "Quantity" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) Par1)) type Rep1 (Dimensional (DUnit m) d :: Type -> Type) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal type Rep1 (Dimensional (DUnit m) d :: Type -> Type) = D1 (MetaData "Dimensional" "Numeric.Units.Dimensional.Internal" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" False) (C1 (MetaCons "Unit" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (UnitName m)) :*: (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ExactPi) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) Par1))) type Rep (Dimensional (DQuantity s) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal type Rep (Dimensional (DQuantity s) d a) = D1 (MetaData "Dimensional" "Numeric.Units.Dimensional.Internal" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" True) (C1 (MetaCons "Quantity" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 a))) type Rep (Dimensional (DUnit m) d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal type Rep (Dimensional (DUnit m) d a) = D1 (MetaData "Dimensional" "Numeric.Units.Dimensional.Internal" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" False) (C1 (MetaCons "Unit" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 (UnitName m)) :*: (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 ExactPi) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 a)))) data Vector (SQuantity s d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal data Vector (SQuantity s d a) = V_Quantity {unVQ :: Vector a}

type Unit (m :: Metricality) = Dimensional (DUnit m) Source #

A unit of measurement.

A dimensional quantity.

Encodes whether a unit is a metric unit, that is, whether it can be combined with a metric prefix to form a related unit.

Constructors

 Metric Capable of receiving a metric prefix. NonMetric Incapable of receiving a metric prefix.
Instances
 Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants Methods Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants Methodsgfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Metricality -> c Metricality #gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Metricality #dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Metricality) #dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Metricality) #gmapT :: (forall b. Data b => b -> b) -> Metricality -> Metricality #gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Metricality -> r #gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Metricality -> r #gmapQ :: (forall d. Data d => d -> u) -> Metricality -> [u] #gmapQi :: Int -> (forall d. Data d => d -> u) -> Metricality -> u #gmapM :: Monad m => (forall d. Data d => d -> m d) -> Metricality -> m Metricality #gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Metricality -> m Metricality #gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Metricality -> m Metricality # Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants Methods Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants Associated Typestype Rep Metricality :: Type -> Type # Methods Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants Methodsrnf :: Metricality -> () # type Rep Metricality Source # Instance detailsDefined in Numeric.Units.Dimensional.Variants type Rep Metricality = D1 (MetaData "Metricality" "Numeric.Units.Dimensional.Variants" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" False) (C1 (MetaCons "Metric" PrefixI False) (U1 :: Type -> Type) :+: C1 (MetaCons "NonMetric" PrefixI False) (U1 :: Type -> Type))

# Physical Dimensions

The phantom type variable d encompasses the physical dimension of a Dimensional. As detailed in [5] there are seven base dimensions, which can be combined in integer powers to a given physical dimension. We represent physical dimensions as the powers of the seven base dimensions that make up the given dimension. The powers are represented using NumTypes. For convenience we collect all seven base dimensions in a data kind Dimension.

We could have chosen to provide type variables for the seven base dimensions in Dimensional instead of creating a new data kind Dimension. However, that would have made any type signatures involving Dimensional very cumbersome. By encompassing the physical dimension in a single type variable we can "hide" the cumbersome type arithmetic behind convenient type classes as will be seen later.

data Dimension Source #

Represents a physical dimension in the basis of the 7 SI base dimensions, where the respective dimensions are represented by type variables using the following convention:

• l: Length
• m: Mass
• t: Time
• i: Electric current
• th: Thermodynamic temperature
• n: Amount of substance
• j: Luminous intensity

For the equivalent term-level representation, see Dimension'

Constructors

 Dim TypeInt TypeInt TypeInt TypeInt TypeInt TypeInt TypeInt
Instances
 (KnownTypeInt l, KnownTypeInt m, KnownTypeInt t, KnownTypeInt i, KnownTypeInt th, KnownTypeInt n, KnownTypeInt j) => HasDimension (Proxy (Dim l m t i th n j)) Source # Instance details Methodsdimension :: Proxy (Dim l m t i th n j) -> Dimension' Source # (KnownTypeInt l, KnownTypeInt m, KnownTypeInt t, KnownTypeInt i, KnownTypeInt th, KnownTypeInt n, KnownTypeInt j) => HasDynamicDimension (Proxy (Dim l m t i th n j)) Source # Instance details MethodsdynamicDimension :: Proxy (Dim l m t i th n j) -> DynamicDimension Source #

## Dimension Arithmetic

When performing arithmetic on units and quantities the arithmetics must be applied to both the numerical values of the Dimensionals but also to their physical dimensions. The type level arithmetic on physical dimensions is governed by closed type families expressed as type operators.

We could provide the Mul and Div classes with full functional dependencies but that would be of limited utility as there is no limited use for "backwards" type inference. Efforts are underway to develop a type-checker plugin that does enable these scenarios, e.g. for linear algebra.

type family (a :: Dimension) * (b :: Dimension) where ... infixl 7 Source #

Multiplication of dimensions corresponds to adding of the base dimensions' exponents.

Equations

 DOne * d = d d * DOne = d (Dim l m t i th n j) * (Dim l' m' t' i' th' n' j') = Dim (l + l') (m + m') (t + t') (i + i') (th + th') (n + n') (j + j')

type family (a :: Dimension) / (d :: Dimension) where ... infixl 7 Source #

Division of dimensions corresponds to subtraction of the base dimensions' exponents.

Equations

 d / DOne = d d / d = DOne (Dim l m t i th n j) / (Dim l' m' t' i' th' n' j') = Dim (l - l') (m - m') (t - t') (i - i') (th - th') (n - n') (j - j')

type family (d :: Dimension) ^ (x :: TypeInt) where ... infixr 8 Source #

Powers of dimensions corresponds to multiplication of the base dimensions' exponents by the exponent.

We limit ourselves to integer powers of Dimensionals as fractional powers make little physical sense.

Equations

 DOne ^ x = DOne d ^ Zero = DOne d ^ Pos1 = d (Dim l m t i th n j) ^ x = Dim (l * x) (m * x) (t * x) (i * x) (th * x) (n * x) (j * x)

type family NRoot (d :: Dimension) (x :: TypeInt) where ... Source #

Roots of dimensions corresponds to division of the base dimensions' exponents by the order of the root.

Equations

 NRoot DOne x = DOne NRoot d Pos1 = d NRoot (Dim l m t i th n j) x = Dim (l / x) (m / x) (t / x) (i / x) (th / x) (n / x) (j / x)

type Sqrt d = NRoot d Pos2 Source #

Square root is a special case of NRoot with order 2.

type Cbrt d = NRoot d Pos3 Source #

Cube root is a special case of NRoot with order 3.

type Recip (d :: Dimension) = DOne / d Source #

The reciprocal of a dimension is defined as the result of dividing DOne by it, or of negating each of the base dimensions' exponents.

## Term Level Representation of Dimensions

To facilitate parsing and pretty-printing functions that may wish to operate on term-level representations of dimension, we provide a means for converting from type-level dimensions to term-level dimensions.

A physical dimension, encoded as 7 integers, representing a factorization of the dimension into the 7 SI base dimensions. By convention they are stored in the same order as in the Dimension data kind.

Constructors

 Dim' !Int !Int !Int !Int !Int !Int !Int
Instances
 Source # Instance details Methods Source # Instance details Methodsgfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Dimension' -> c Dimension' #gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c Dimension' #dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c Dimension') #dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c Dimension') #gmapT :: (forall b. Data b => b -> b) -> Dimension' -> Dimension' #gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Dimension' -> r #gmapQr :: (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Dimension' -> r #gmapQ :: (forall d. Data d => d -> u) -> Dimension' -> [u] #gmapQi :: Int -> (forall d. Data d => d -> u) -> Dimension' -> u #gmapM :: Monad m => (forall d. Data d => d -> m d) -> Dimension' -> m Dimension' #gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Dimension' -> m Dimension' #gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Dimension' -> m Dimension' # Source # Instance details Methods Source # Instance details MethodsshowList :: [Dimension'] -> ShowS # Source # Instance details Associated Typestype Rep Dimension' :: Type -> Type # Methods Source # Instance details Methodsstimes :: Integral b => b -> Dimension' -> Dimension' # Source # The monoid of dimensions under multiplication. Instance details Methodsmconcat :: [Dimension'] -> Dimension' # Source # Instance details Methodsrnf :: Dimension' -> () # Source # Instance details Methods Source # Instance details Methods type Rep Dimension' Source # Instance details type Rep Dimension' = D1 (MetaData "Dimension'" "Numeric.Units.Dimensional.Dimensions.TermLevel" "dimensional-1.3-7Gh1mp5ZBGaGfkDr7lUYf2" False) (C1 (MetaCons "Dim'" PrefixI False) ((S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int) :*: (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int))) :*: ((S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int)) :*: (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int) :*: S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 Int)))))

class HasDynamicDimension a => HasDimension a where Source #

Dimensional values inhabit this class, which allows access to a term-level representation of their dimension.

Methods

dimension :: a -> Dimension' Source #

Obtains a term-level representation of a value's dimension.

Instances
 Source # Instance details Methods Source # Instance detailsDefined in Numeric.Units.Dimensional.Dynamic Methods Source # Instance detailsDefined in Numeric.Units.Dimensional.Dynamic Methods (KnownTypeInt l, KnownTypeInt m, KnownTypeInt t, KnownTypeInt i, KnownTypeInt th, KnownTypeInt n, KnownTypeInt j) => HasDimension (Proxy (Dim l m t i th n j)) Source # Instance details Methodsdimension :: Proxy (Dim l m t i th n j) -> Dimension' Source # KnownDimension d => HasDimension (Dimensional v d a) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Methodsdimension :: Dimensional v d a -> Dimension' Source #

type KnownDimension (d :: Dimension) = HasDimension (Proxy d) Source #

A KnownDimension is one for which we can construct a term-level representation. Each validly constructed type of kind Dimension has a KnownDimension instance.

While KnownDimension is a constraint synonym, the presence of KnownDimension d in a context allows use of dimension :: Proxy d -> Dimension'.

# Dimensional Arithmetic

(*~) :: Num a => a -> Unit m d a -> Quantity d a infixl 7 Source #

Forms a Quantity by multipliying a number and a unit.

(/~) :: Fractional a => Quantity d a -> Unit m d a -> a infixl 7 Source #

Divides a Quantity by a Unit of the same physical dimension, obtaining the numerical value of the quantity expressed in that unit.

(^) :: (Fractional a, KnownTypeInt i, KnownVariant v, KnownVariant (Weaken v)) => Dimensional v d1 a -> Proxy i -> Dimensional (Weaken v) (d1 ^ i) a infixr 8 Source #

Raises a Quantity or Unit to an integer power.

Because the power chosen impacts the Dimension of the result, it is necessary to supply a type-level representation of the exponent in the form of a Proxy to some TypeInt. Convenience values pos1, pos2, neg1, ... are supplied by the Numeric.NumType.DK.Integers module. The most commonly used ones are also reexported by Numeric.Units.Dimensional.Prelude.

The intimidating type signature captures the similarity between these operations and ensures that composite Units are NotPrefixable.

(^/) :: (KnownTypeInt n, Floating a) => Quantity d a -> Proxy n -> Quantity (NRoot d n) a infixr 8 Source #

Computes the nth root of a Quantity using **.

The NRoot type family will prevent application of this operator where the result would have a fractional dimension or where n is zero.

Because the root chosen impacts the Dimension of the result, it is necessary to supply a type-level representation of the root in the form of a Proxy to some TypeInt. Convenience values pos1, pos2, neg1, ... are supplied by the Numeric.NumType.DK.Integers module. The most commonly used ones are also reexported by Numeric.Units.Dimensional.Prelude.

Also available in prefix form, see nroot.

(**) :: Floating a => Dimensionless a -> Dimensionless a -> Dimensionless a infixr 8 Source #

Raises a dimensionless quantity to a dimensionless power.

(*) :: (KnownVariant v1, KnownVariant v2, KnownVariant (v1 * v2), Num a) => Dimensional v1 d1 a -> Dimensional v2 d2 a -> Dimensional (v1 * v2) (d1 * d2) a infixl 7 Source #

Multiplies two Quantitys or two Units.

The intimidating type signature captures the similarity between these operations and ensures that composite Units are NonMetric.

(/) :: (KnownVariant v1, KnownVariant v2, KnownVariant (v1 / v2), Fractional a) => Dimensional v1 d1 a -> Dimensional v2 d2 a -> Dimensional (v1 / v2) (d1 / d2) a infixl 7 Source #

Divides one Quantity by another or one Unit by another.

The intimidating type signature captures the similarity between these operations and ensures that composite Units are NotPrefixable.

(+) :: Num a => Quantity d a -> Quantity d a -> Quantity d a infixl 6 Source #

Adds two Quantitys.

(-) :: Num a => Quantity d a -> Quantity d a -> Quantity d a infixl 6 Source #

Subtracts one Quantity from another.

negate :: Num a => Quantity d a -> Quantity d a Source #

Negates the value of a Quantity.

abs :: Num a => Quantity d a -> Quantity d a Source #

Takes the absolute value of a Quantity.

signum :: Num a => Quantity d a -> Dimensionless a Source #

Takes the sign of a Quantity. The functions abs and signum satisy the law that:

abs x * signum x == x

The sign is either negate _1 (negative), _0 (zero), or _1 (positive).

recip :: Fractional a => Quantity d a -> Quantity (Recip d) a Source #

Forms the reciprocal of a Quantity, which has the reciprocal dimension.

148.0 W


# On Functor, and Conversion Between Number Representations

We intentionally decline to provide a Functor instance for Dimensional because its use breaks the abstraction of physical dimensions.

If you feel your work requires this instance, it is provided as an orphan in Numeric.Units.Dimensional.Functor.

class KnownVariant (v :: Variant) where Source #

A KnownVariant is one whose term-level Dimensional values we can represent with an associated data family instance and manipulate with certain functions, not all of which are exported from the package.

Each validly constructed type of kind Variant has a KnownVariant instance.

Minimal complete definition

extractValue, extractName, injectValue, dmap

Methods

dmap :: (a1 -> a2) -> Dimensional v d a1 -> Dimensional v d a2 Source #

Maps over the underlying representation of a dimensional value. The caller is responsible for ensuring that the supplied function respects the dimensional abstraction. This means that the function must preserve numerical values, or linearly scale them while preserving the origin.

Instances
 Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typesdata Dimensional (DQuantity s) a b :: Type Source #type ScaleFactor (DQuantity s) :: ExactPi' MethodsextractValue :: Dimensional (DQuantity s) d a -> (a, Maybe ExactPi)extractName :: Dimensional (DQuantity s) d a -> Maybe (UnitName NonMetric)injectValue :: Maybe (UnitName NonMetric) -> (a, Maybe ExactPi) -> Dimensional (DQuantity s) d admap :: (a1 -> a2) -> Dimensional (DQuantity s) d a1 -> Dimensional (DQuantity s) d a2 Source # Typeable m => KnownVariant (DUnit m) Source # Instance detailsDefined in Numeric.Units.Dimensional.Internal Associated Typesdata Dimensional (DUnit m) a b :: Type Source #type ScaleFactor (DUnit m) :: ExactPi' MethodsextractValue :: Dimensional (DUnit m) d a -> (a, Maybe ExactPi)extractName :: Dimensional (DUnit m) d a -> Maybe (UnitName NonMetric)injectValue :: Maybe (UnitName NonMetric) -> (a, Maybe ExactPi) -> Dimensional (DUnit m) d admap :: (a1 -> a2) -> Dimensional (DUnit m) d a1 -> Dimensional (DUnit m) d a2 Source #

changeRep :: (KnownVariant v, Real a, Fractional b) => Dimensional v d a -> Dimensional v d b Source #

Convenient conversion between numerical types while retaining dimensional information.

>>> let x = (37 :: Rational) *~ poundMass
>>> changeRep x :: Mass Double
16.78291769 kg


changeRepApproximate :: (KnownVariant v, Floating b) => Dimensional v d ExactPi -> Dimensional v d b Source #

Convenient conversion from exactly represented values while retaining dimensional information.

# Lenses

These functions are compatible with the lens library.

asLens :: Fractional a => Unit m d a -> forall f. Functor f => (a -> f a) -> Quantity d a -> f (Quantity d a) Source #

Converts a Unit into a lens from Quantity`s to values.