Copyright | (C) 2014 Richard Eisenberg |
---|---|

License | BSD-style (see LICENSE) |

Maintainer | Richard Eisenberg (rae@cs.brynmawr.edu) |

Stability | experimental |

Portability | non-portable |

Safe Haskell | None |

Language | Haskell2010 |

This module exports Template Haskell functions to make working with
`units`

a little more convenient.

## Synopsis

- evalType :: Q Type -> Q Type
- declareDimension :: String -> Q [Dec]
- declareCanonicalUnit :: String -> Q Type -> Maybe String -> Q [Dec]
- declareDerivedUnit :: String -> Q Type -> Rational -> Maybe String -> Q [Dec]
- declareMonoUnit :: String -> Maybe String -> Q [Dec]
- declareConstant :: String -> Rational -> Q Type -> Q [Dec]

# Documentation

evalType :: Q Type -> Q Type Source #

Evaluates a type as far as it can. This is useful, say, in instance declarations:

instance Show $(evalType [t| Length |]) where ...

Without the `evalType`

, the instance declaration fails because `Length`

mentions type families, which can't be used in instance declarations.

This function is somewhat experimental, and will likely not work with
more polymorphic types. (If it doesn't work, not all of the type families
will be evaluated, and the instance declaration will fail. This function
should never cause *incorrect* behavior.)

declareDimension :: String -> Q [Dec] Source #

Declare a new dimension of the given name:

$(declareDimension "Length")

produces

data Length = Length instance Dimension Length

declareCanonicalUnit :: String -> Q Type -> Maybe String -> Q [Dec] Source #

`declareCanonicalUnit unit_name dim (Just abbrev)`

creates a new
canonical unit (that is, it is not defined in terms of other known units)
named `unit_name`

, measuring dimension `dim`

. `abbrev`

will be the
abbreviation in the unit's `Show`

instance. If no abbraviation is supplied,
then no `Show`

instance will be generated.

Example usage:

$(declareCanonicalUnit "Meter" [t| Length |] (Just "m"))

declareDerivedUnit :: String -> Q Type -> Rational -> Maybe String -> Q [Dec] Source #

`declareDerivedUnit unit_name base_unit_type ratio (Just abbrev)`

creates
a new derived unit, expressed in terms of `base_unit_type`

. `ratio`

says
how many base units are in the derived unit. (Thus, if `unit_name`

is
`Minute`

and `base_unit_type`

is `''Second`

, then `ratio`

would be `60`

.)
`abbrev`

, if supplied, becomes the string produced in the derived unit's
`Show`

instance. If no abbreviation is supplied, no `Show`

instance is
generated.

Example usage:

$(declareDerivedUnit "Minute" [t| Second |] 60 (Just "min"))

declareMonoUnit :: String -> Maybe String -> Q [Dec] Source #

`declareMonoUnit unit_name (Just abbrev)`

creates a new derived unit,
intended for use without unit polymorphism. The same type stands for both
the unit and dimension, and the instance of `DefaultUnitOfDim`

is set up
accordingly. Use this function (with the `Metrology`

imports) if you
don't want to bother with LCSUs and just want to get to work. The `abbrev`

,
if supplied, creates an appropriate `Show`

instance.

$(declareMonoUnit "Meter" (Just "m"))

produces all of the following

data Meter = Meter instance Dimension Meter instance Unit Meter where type BaseUnit Meter = Canonical type DimOfUnit Meter = Meter type instance DefaultUnitOfDim Meter = Meter instance Show Meter where show _ = "m"

After a declaration like this, you probably want

type Length = MkQu_U Meter

This last line is *not* generated, as it is easy enough for you to write,
and it involves a new name (`Length`

).

declareConstant :: String -> Rational -> Q Type -> Q [Dec] Source #

`declareConstant const_name value unit_type`

creates a new numerical
constant, named `const_name`

. Its numerical value is `value`

expressed
in units given by `unit_type`

. The constant is polymorphic in both its
LCSU and numerical representation. For example,

declareConstant "gravity_g" 9.80665 [t| Meter :/ Second :^ Two |]

yields

gravity_g :: ( Fractional n , CompatibleUnit lcsu (Meter :/ Second :^ Two) ) => MkQu_ULN (Meter :/ Second :^ Two) lcsu n gravity_g = 9.80665 % (undefined :: Meter :/ Second :^ Two)