units 1.0.1 → 1.1
raw patch · 28 files changed
+1463/−1467 lines, 28 filesdep +singletons
Dependencies added: singletons
Files
- CHANGES.md +13/−2
- Data/Dimensions.hs +145/−0
- Data/Dimensions/Dim.hs +149/−0
- Data/Dimensions/DimSpec.hs +166/−0
- Data/Dimensions/Poly.hs +41/−0
- Data/Dimensions/SI.hs +29/−0
- Data/Dimensions/SI/Prefixes.hs +217/−0
- Data/Dimensions/SI/Types.hs +59/−0
- Data/Dimensions/SI/Units.hs +179/−0
- Data/Dimensions/Show.hs +73/−0
- Data/Dimensions/UnitCombinators.hs +72/−0
- Data/Dimensions/Units.hs +112/−0
- Data/Dimensions/Unsafe.hs +22/−0
- Data/Dimensions/Z.hs +148/−0
- README.md +31/−26
- src/Data/Dimensions.hs +0/−140
- src/Data/Dimensions/Dim.hs +0/−148
- src/Data/Dimensions/DimSpec.hs +0/−192
- src/Data/Dimensions/Internal.hs +0/−38
- src/Data/Dimensions/SI.hs +0/−180
- src/Data/Dimensions/SI/Prefixes.hs +0/−217
- src/Data/Dimensions/SI/Types.hs +0/−56
- src/Data/Dimensions/Show.hs +0/−71
- src/Data/Dimensions/TypePrelude.hs +0/−45
- src/Data/Dimensions/UnitCombinators.hs +0/−72
- src/Data/Dimensions/Units.hs +0/−108
- src/Data/Dimensions/Z.hs +0/−165
- units.cabal +7/−7
CHANGES.md view
@@ -1,9 +1,20 @@+Version 1.1+-----------++* Added dependency on the singletons library++* Brought up to date with changes for GHC 7.8++* Generalized numerical representation++* Improved Haddock headers+ Version 1.0.1-=============+------------- * Fixed dependency on base to force compilation with GHC >= 7.7 Version 1.0-===========+----------- * First release
+ Data/Dimensions.hs view
@@ -0,0 +1,145 @@+{- Data/Dimensions.hs++ The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file gathers and exports all user-visible pieces of the units package.+ It also defines the main creators and consumers of dimensioned objects.++ This package declares many closely-related types. The following naming+ conventions should be helpful:++ Prefix Target type/kind+ ------------------------+ # Z+ $ DimSpec *+ @ [DimSpec *]+ @@ [DimSpec *], where the arguments are ordered similarly+ % Dim (at the type level)+ . Dim (at the term level)+ : units, at both type and term levels+-}++{-# LANGUAGE ExplicitNamespaces, DataKinds, FlexibleInstances, TypeFamilies,+ TypeOperators, ConstraintKinds #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- The units package is a framework for strongly-typed dimensional analysis.+-- This haddock documentation is generally /not/ enough to be able to use this+-- package effectively. Please see the readme at+-- <http://www.cis.upenn.edu/~eir/packages/units/README.html>.+--+-- Some of the types below refer to declarations that are not exported and+-- not documented here. This is because Haddock does not allow finely-tuned+-- abstraction in documentation. (In particular, right-hand sides of type +-- synonym declarations are always included.) If a symbol is not exported,+-- you do /not/ need to know anything about it to use this package.+--+-- Though it doesn't appear here, @Scalar@ is an instance of @Num@, and+-- generally has all the numeric instances that @Double@ has.+-----------------------------------------------------------------------------++module Data.Dimensions (+ -- * Term-level combinators+ (.+), (.-), (.*), (./), (.^), (*.),+ (.<), (.>), (.<=), (.>=), dimEq, dimNeq,+ nthRoot, dimSqrt, dimCubeRoot,+ unity, zero, dim,+ dimIn, (#), dimOf, (%),++ -- * Type-level unit combinators+ (:*)(..), (:/)(..), (:^)(..), (:@)(..),+ UnitPrefix(..),++ -- * Type-level dimensioned-quantity combinators+ type (%*), type (%/), type (%^),++ -- * Creating new units+ Unit(type BaseUnit, conversionRatio), MkDim, MkGenDim, Canonical, ++ -- * Scalars, the only built-in unit+ Number(..), Scalar, scalar,++ -- * Type-level integers+ Z(..), Succ, Pred, type (#+), type (#-), type (#*), type (#/), NegZ,++ -- ** Synonyms for small numbers+ One, Two, Three, Four, Five, MOne, MTwo, MThree, MFour, MFive,++ -- ** Term-level singletons+ pZero, pOne, pTwo, pThree, pFour, pFive,+ pMOne, pMTwo, pMThree, pMFour, pMFive,+ pSucc, pPred++ ) where++import Data.Dimensions.Z+import Data.Dimensions.Dim+import Data.Dimensions.DimSpec+import Data.Dimensions.Units+import Data.Dimensions.UnitCombinators++-- | Extracts a @Double@ from a dimensioned quantity, expressed in+-- the given unit. For example:+--+-- > inMeters :: Length -> Double+-- > inMeters x = dimIn x Meter+dimIn :: Unit unit => MkDim (CanonicalUnit unit) -> unit -> Double+dimIn (Dim val) u = val / canonicalConvRatio u++infix 5 #+-- | Infix synonym for 'dimIn'+(#) :: Unit unit => MkDim (CanonicalUnit unit) -> unit -> Double+(#) = dimIn++-- | Creates a dimensioned quantity in the given unit. For example:+--+-- > height :: Length+-- > height = dimOf 2.0 Meter+dimOf :: Unit unit => Double -> unit -> MkDim (CanonicalUnit unit)+dimOf d u = Dim (d * canonicalConvRatio u)++infix 9 %+-- | Infix synonym for 'dimOf'+(%) :: Unit unit => Double -> unit -> MkDim (CanonicalUnit unit)+(%) = dimOf++-- | The number 1, expressed as a unitless dimensioned quantity.+unity :: Num n => Dim n '[]+unity = Dim 1++-- | The number 0, polymorphic in its dimension. Use of this will+-- often require a type annotation.+zero :: Num n => Dim n dimspec+zero = Dim 0++-- | Dimension-safe cast. See the README for more info.+dim :: (d @~ e) => Dim n d -> Dim n e+dim (Dim x) = Dim x++-------------------------------------------------------------+--- "Number" unit -------------------------------------------+-------------------------------------------------------------++-- | The unit for unitless dimensioned quantities+data Number = Number -- the unit for unadorned numbers+instance Unit Number where+ type BaseUnit Number = Canonical+ type DimSpecsOf Number = '[]++-- | The type of unitless dimensioned quantities+-- This is an instance of @Num@, though Haddock doesn't show it.+type Scalar = MkDim Number++-- | Convert a raw number into a unitless dimensioned quantity+scalar :: n -> Dim n '[]+scalar = Dim
+ Data/Dimensions/Dim.hs view
@@ -0,0 +1,149 @@+{- Data/Dimensions.hs++ The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file defines the Dim type and operations on that type.+-}++{-# LANGUAGE TypeFamilies, TypeOperators, DataKinds, UndecidableInstances,+ ConstraintKinds, StandaloneDeriving, GeneralizedNewtypeDeriving,+ FlexibleInstances #-}++module Data.Dimensions.Dim where++import Data.Singletons ( Sing )+import Data.Dimensions.DimSpec+import Data.Dimensions.Z++-------------------------------------------------------------+--- Internal ------------------------------------------------+-------------------------------------------------------------++-- | Dim adds a dimensional annotation to its base type @n@. This is the+-- representation for all dimensioned quantities.+newtype Dim (n :: *) (a :: [DimSpec *]) = Dim n++-------------------------------------------------------------+--- User-facing ---------------------------------------------+-------------------------------------------------------------++infixl 6 .++-- | Add two compatible dimensioned quantities+(.+) :: (d1 @~ d2, Num n) => Dim n d1 -> Dim n d2 -> Dim n d1+(Dim a) .+ (Dim b) = Dim (a + b)++infixl 6 .-+-- | Subtract two compatible dimensioned quantities+(.-) :: (d1 @~ d2, Num n) => Dim n d1 -> Dim n d2 -> Dim n d1+(Dim a) .- (Dim b) = Dim (a - b)++infixl 7 .*+-- | Multiply two dimensioned quantities+(.*) :: Num n => Dim n a -> Dim n b -> Dim n (Normalize (a @+ b))+(Dim a) .* (Dim b) = Dim (a * b)++infixl 7 ./+-- | Divide two dimensioned quantities+(./) :: Fractional n => Dim n a -> Dim n b -> Dim n (Normalize (a @- b))+(Dim a) ./ (Dim b) = Dim (a / b)++infixr 8 .^+-- | Raise a dimensioned quantity to a power known at compile time+(.^) :: Fractional n => Dim n a -> Sing z -> Dim n (a @* z)+(Dim a) .^ sz = Dim (a ^^ szToInt sz)++-- | Take the n'th root of a dimensioned quantity, where n is known at compile+-- time+nthRoot :: ((Zero < z) ~ True, Floating n) => Sing z -> Dim n a -> Dim n (a @/ z)+nthRoot sz (Dim a) = Dim (a ** (1.0 / (fromIntegral $ szToInt sz)))++infix 4 .<+-- | Check if one dimensioned quantity is less than a compatible one+(.<) :: (d1 @~ d2, Ord n) => Dim n d1 -> Dim n d2 -> Bool+(Dim a) .< (Dim b) = a < b++infix 4 .>+-- | Check if one dimensioned quantity is greater than a compatible one+(.>) :: (d1 @~ d2, Ord n) => Dim n d1 -> Dim n d2 -> Bool+(Dim a) .> (Dim b) = a > b++infix 4 .<=+-- | Check if one dimensioned quantity is less than or equal to a compatible one+(.<=) :: (d1 @~ d2, Ord n) => Dim n d1 -> Dim n d2 -> Bool+(Dim a) .<= (Dim b) = a <= b++infix 4 .>=+-- | Check if one dimensioned quantity is greater than or equal to a compatible one+(.>=) :: (d1 @~ d2, Ord n) => Dim n d1 -> Dim n d2 -> Bool+(Dim a) .>= (Dim b) = a >= b++-- | Compare two compatible dimensioned quantities for equality+dimEq :: (d0 @~ d1, d0 @~ d2, Num n, Ord n)+ => Dim n d0 -- ^ If the difference between the next+ -- two arguments are less than this + -- amount, they are considered equal+ -> Dim n d1 -> Dim n d2 -> Bool+dimEq (Dim epsilon) (Dim a) (Dim b) = abs(a-b) < epsilon++-- | Compare two compatible dimensioned quantities for inequality+dimNeq :: (d0 @~ d1, d0 @~ d2, Num n, Ord n)+ => Dim n d0 -- ^ If the difference between the next+ -- two arguments are less than this + -- amount, they are considered equal+ -> Dim n d1 -> Dim n d2 -> Bool+dimNeq (Dim epsilon) (Dim a) (Dim b) = abs(a-b) >= epsilon++-- | Square a dimensioned quantity+dimSqr :: Num n => Dim n a -> Dim n (Normalize (a @+ a))+dimSqr x = x .* x++-- | Take the square root of a dimensioned quantity+dimSqrt :: Floating n => Dim n a -> Dim n (a @/ Two)+dimSqrt = nthRoot pTwo++-- | Take the cube root of a dimensioned quantity+dimCubeRoot :: Floating n => Dim n a -> Dim n (a @/ Three)+dimCubeRoot = nthRoot pThree++infixl 7 *.+-- | Multiply a dimensioned quantity by a scalar+(*.) :: Num n => n -> Dim n a -> Dim n a+a *. (Dim b) = Dim (a * b)++-------------------------------------------------------------+--- Instances -----------------------------------------------+-------------------------------------------------------------++deriving instance Eq n => Eq (Dim n '[])+deriving instance Ord n => Ord (Dim n '[])+deriving instance Num n => Num (Dim n '[])+deriving instance Real n => Real (Dim n '[])+deriving instance Fractional n => Fractional (Dim n '[])+deriving instance Floating n => Floating (Dim n '[])+deriving instance RealFrac n => RealFrac (Dim n '[])+deriving instance RealFloat n => RealFloat (Dim n '[])++-------------------------------------------------------------+--- Combinators ---------------------------------------------+-------------------------------------------------------------++infixl 7 %*+-- | Multiply two dimension types to produce a new one. For example:+--+-- > type Velocity = Length %/ Time+type family (d1 :: *) %* (d2 :: *) :: *+type instance (Dim n d1) %* (Dim n d2) = Dim n (d1 @+ d2)++infixl 7 %/+-- | Divide two dimension types to produce a new one+type family (d1 :: *) %/ (d2 :: *) :: *+type instance (Dim n d1) %/ (Dim n d2) = Dim n (d1 @- d2)++infixr 8 %^+-- | Exponentiate a dimension type to an integer+type family (d :: *) %^ (z :: Z) :: *+type instance (Dim n d) %^ z = Dim n (d @* z)++
+ Data/Dimensions/DimSpec.hs view
@@ -0,0 +1,166 @@+{- Data/Dimensions/DimSpec.hs++ The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file defines the DimSpec kind and operations over lists of DimSpecs+-}++{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators, UndecidableInstances #-}++module Data.Dimensions.DimSpec where++import GHC.Exts (Constraint)+import Data.Dimensions.Z+import Data.Type.Equality+import Data.Type.Bool++import Data.Singletons.Tuple (Fst, Snd)++-- | This will only be used at the kind level. It holds a dimension with its+-- exponent.+data DimSpec star = D star Z++----------------------------------------------------------+--- Set-like operations ----------------------------------+----------------------------------------------------------+{-+These functions are templates for type-level functions.+remove :: String -> [String] -> [String]+remove _ [] = []+remove s (h:t) = if s == h then t else h : remove s t++member :: String -> [String] -> Bool+member _ [] = False+member s (h:t) = s == h || member s t++extract :: String -> [String] -> ([String], Maybe String)+extract _ [] = ([], Nothing)+extract s (h:t) =+ if s == h+ then (t, Just s)+ else let (resList, resVal) = extract s t in (h : resList, resVal)++reorder :: [String] -> [String] -> [String]+reorder x [] = x+reorder x (h:t) =+ case extract h x of+ (lst, Nothing) -> reorder lst t+ (lst, Just elt) -> elt : (reorder lst t)+-}++infix 4 $=+-- | Do these DimSpecs represent the same dimension?+type family (a :: DimSpec *) $= (b :: DimSpec *) :: Bool where+ (D n1 z1) $= (D n2 z2) = n1 == n2+ a $= b = False++-- | @(Extract s lst)@ pulls the DimSpec that matches s out of lst, returning a+-- diminished list and, possibly, the extracted DimSpec.+--+-- @+-- Extract A [A, B, C] ==> ([B, C], Just A+-- Extract D [A, B, C] ==> ([A, B, C], Nothing)+-- @+type family Extract (s :: DimSpec *)+ (lst :: [DimSpec *])+ :: ([DimSpec *], Maybe (DimSpec *)) where+ Extract s '[] = '( '[], Nothing )+ Extract s (h ': t) =+ If (s $= h)+ '(t, Just h)+ '(h ': Fst (Extract s t), Snd (Extract s t))++-- kind DimAnnotation = [DimSpec *]+-- a list of DimSpecs forms a full annotation of a quantity's dimension++-- | Reorders a to be the in the same order as b, putting entries not in b at the end+--+-- @+-- Reorder [A 1, B 2] [B 5, A 2] ==> [B 2, A 1]+-- Reorder [A 1, B 2, C 3] [C 2, A 8] ==> [C 3, A 1, B 2]+-- Reorder [A 1, B 2] [B 4, C 1, A 9] ==> [B 2, A 1]+-- Reorder x x ==> x+-- Reorder x [] ==> x+-- Reorder [] x ==> []+-- @+type family Reorder (a :: [DimSpec *]) (b :: [DimSpec *]) :: [DimSpec *] where+ Reorder x x = x+ Reorder x '[] = x+ Reorder x (h ': t) = Reorder' (Extract h x) t++-- | Helper function in 'Reorder'+type family Reorder' (scrut :: ([DimSpec *], Maybe (DimSpec *)))+ (t :: [DimSpec *])+ :: [DimSpec *] where+ Reorder' '(lst, Nothing) t = Reorder lst t+ Reorder' '(lst, Just elt) t = elt ': (Reorder lst t)++infix 4 @~+-- | Check if two @[DimSpec *]@s should be considered to be equal+type family (a :: [DimSpec *]) @~ (b :: [DimSpec *]) :: Constraint where+ a @~ b = (Normalize (Reorder a b) ~ Normalize b)++----------------------------------------------------------+--- Normalization ----------------------------------------+----------------------------------------------------------++-- | Take a @[DimSpec *]@ and remove any @DimSpec@s with an exponent of 0+type family Normalize (d :: [DimSpec *]) :: [DimSpec *] where+ Normalize '[] = '[]+ Normalize ((D n Zero) ': t) = Normalize t+ Normalize (h ': t) = h ': Normalize t++----------------------------------------------------------+--- Arithmetic -------------------------------------------+----------------------------------------------------------++infixl 6 @@++-- | Adds corresponding exponents in two dimension, assuming the lists are+-- ordered similarly.+type family (a :: [DimSpec *]) @@+ (b :: [DimSpec *]) :: [DimSpec *] where+ '[] @@+ b = b+ a @@+ '[] = a+ ((D name z1) ': t1) @@+ ((D name z2) ': t2) = (D name (z1 #+ z2)) ': (t1 @@+ t2)+ a @@+ (h ': t) = h ': (a @@+ t)++infixl 6 @++-- | Adds corresponding exponents in two dimension+type family (a :: [DimSpec *]) @+ (b :: [DimSpec *]) :: [DimSpec *] where+ a @+ b = (Reorder a b) @@+ b++infixl 6 @@-+-- | Subtract exponents in two dimensions, assuming the lists are ordered+-- similarly.+type family (a :: [DimSpec *]) @@- (b :: [DimSpec *]) :: [DimSpec *] where+ '[] @@- b = NegList b+ a @@- '[] = a+ ((D name z1) ': t1) @@- ((D name z2) ': t2) = (D name (z1 #- z2)) ': (t1 @@- t2)+ a @@- (h ': t) = (NegDim h) ': (a @@- t)++infixl 6 @-+-- | Subtract exponents in two dimensions+type family (a :: [DimSpec *]) @- (b :: [DimSpec *]) :: [DimSpec *] where+ a @- b = (Reorder a b) @@- b++-- | negate a single @DimSpec@+type family NegDim (a :: DimSpec *) :: DimSpec * where+ NegDim (D n z) = D n (NegZ z)++-- | negate a list of @DimSpec@s+type family NegList (a :: [DimSpec *]) :: [DimSpec *] where+ NegList '[] = '[]+ NegList (h ': t) = (NegDim h ': (NegList t))++infixl 7 @*+-- | Multiplication of the exponents in a dimension by a scalar+type family (base :: [DimSpec *]) @* (power :: Z) :: [DimSpec *] where+ '[] @* power = '[]+ ((D name num) ': t) @* power = (D name (num #* power)) ': (t @* power)++infixl 7 @/+-- | Division of the exponents in a dimension by a scalar+type family (dims :: [DimSpec *]) @/ (z :: Z) :: [DimSpec *] where+ '[] @/ z = '[]+ ((D name num) ': t) @/ z = (D name (num #/ z)) ': (t @/ z)
+ Data/Dimensions/Poly.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE ExplicitNamespaces #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.Poly+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module exports all of the definitions you need if you wish to+-- write functions polymorphic over dimension specifications.+--+-- Each dimensioned quantity is represented by a member of the type+-- 'Dim', which is parameterized by a type-level list of 'DimSpec's.+-- A 'DimSpec', in turn, is a unit type paired with its exponent,+-- representented with a type-level 'Z'. The unit types should all be+-- /canonical/ -- that is, the "base" unit of all compatible units. Thus,+-- the type of velocity in the SI system would be+-- @Dim '[D Meter One, D Second MOne]@.+--+-- A technical detail: because 'DimSpec' is used only at the type level+-- and needs to store types of kind @*@, it must be parameterized, as we+-- can't specify @*@ in its declaration. (See \"The Right Kind of Generic+-- Programming\", by José Pedro Magalhães, published at WGP'12, for more+-- explanation.) So, we always work with @(DimSpec *)@s.+----------------------------------------------------------------------------++module Data.Dimensions.Poly (+ -- * The 'Dim' type+ Dim,++ -- * Maniuplating dimension specifications+ DimSpec(..), type ($=), Extract, Reorder, type (@~), Normalize,+ type (@+), type (@-), NegDim, NegList, type (@*), type (@/)++ ) where++import Data.Dimensions.Dim+import Data.Dimensions.DimSpec
+ Data/Dimensions/SI.hs view
@@ -0,0 +1,29 @@+{-# LANGUAGE TypeFamilies, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.SI+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module exports unit, type, and prefix definitions according to the SI+-- system of units. The definitions were taken from here:+-- <http://www.bipm.org/en/si/>.+--+-- There is one deviation from the definition at that site: To work better+-- with prefixes, the unit of mass is 'Gram'.+-----------------------------------------------------------------------------++module Data.Dimensions.SI (+ module Data.Dimensions.SI.Units,+ module Data.Dimensions.SI.Types,+ module Data.Dimensions.SI.Prefixes+ ) where++import Data.Dimensions.SI.Units+import Data.Dimensions.SI.Types+import Data.Dimensions.SI.Prefixes+
+ Data/Dimensions/SI/Prefixes.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.SI.Prefixes+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- Defines prefixes from the SI standard at <http://www.bipm.org/en/si/>+-----------------------------------------------------------------------------++module Data.Dimensions.SI.Prefixes where++import Data.Dimensions++-- | 10^1+data Deca = Deca+instance UnitPrefix Deca where+ multiplier _ = 1e1+instance Show Deca where+ show _ = "da"++deca :: unit -> Deca :@ unit+deca = (Deca :@)++-- | 10^2+data Hecto = Hecto+instance UnitPrefix Hecto where+ multiplier _ = 1e2+instance Show Hecto where+ show _ = "h"++hecto :: unit -> Hecto :@ unit+hecto = (Hecto :@)++-- | 10^3+data Kilo = Kilo+instance UnitPrefix Kilo where+ multiplier _ = 1e3+instance Show Kilo where+ show _ = "k"++kilo :: unit -> Kilo :@ unit+kilo = (Kilo :@)++-- | 10^6+data Mega = Mega+instance UnitPrefix Mega where+ multiplier _ = 1e6+instance Show Mega where+ show _ = "M"++mega :: unit -> Mega :@ unit+mega = (Mega :@)++-- | 10^9+data Giga = Giga+instance UnitPrefix Giga where+ multiplier _ = 1e9+instance Show Giga where+ show _ = "G"++giga :: unit -> Giga :@ unit+giga = (Giga :@)++-- | 10^12+data Tera = Tera+instance UnitPrefix Tera where+ multiplier _ = 1e12+instance Show Tera where+ show _ = "T"++tera :: unit -> Tera :@ unit+tera = (Tera :@)++-- | 10^15+data Peta = Peta+instance UnitPrefix Peta where+ multiplier _ = 1e15+instance Show Peta where+ show _ = "P"++peta :: unit -> Peta :@ unit+peta = (Peta :@)++-- | 10^18+data Exa = Exa+instance UnitPrefix Exa where+ multiplier _ = 1e18+instance Show Exa where+ show _ = "E"++exa :: unit -> Exa :@ unit+exa = (Exa :@)++-- | 10^21+data Zetta = Zetta+instance UnitPrefix Zetta where+ multiplier _ = 1e21+instance Show Zetta where+ show _ = "Z"++zetta :: unit -> Zetta :@ unit+zetta = (Zetta :@)++-- | 10^24+data Yotta = Yotta+instance UnitPrefix Yotta where+ multiplier _ = 1e24+instance Show Yotta where+ show _ = "Y"++yotta :: unit -> Yotta :@ unit+yotta = (Yotta :@)++-- | 10^-1+data Deci = Deci+instance UnitPrefix Deci where+ multiplier _ = 1e-1+instance Show Deci where+ show _ = "d"++deci :: unit -> Deci :@ unit+deci = (Deci :@)++-- | 10^-2+data Centi = Centi+instance UnitPrefix Centi where+ multiplier _ = 1e-2+instance Show Centi where+ show _ = "c"++centi :: unit -> Centi :@ unit+centi = (Centi :@)++-- | 10^-3+data Milli = Milli+instance UnitPrefix Milli where+ multiplier _ = 1e-3+instance Show Milli where+ show _ = "m"++milli :: unit -> Milli :@ unit+milli = (Milli :@)++-- | 10^-6+data Micro = Micro+instance UnitPrefix Micro where+ multiplier _ = 1e-6+instance Show Micro where+ show _ = "μ"++micro :: unit -> Micro :@ unit+micro = (Micro :@)++-- | 10^-9+data Nano = Nano+instance UnitPrefix Nano where+ multiplier _ = 1e-9+instance Show Nano where+ show _ = "n"++nano :: unit -> Nano :@ unit+nano = (Nano :@)++-- | 10^-12+data Pico = Pico+instance UnitPrefix Pico where+ multiplier _ = 1e-12+instance Show Pico where+ show _ = "p"++pico :: unit -> Pico :@ unit+pico = (Pico :@)++-- | 10^-15+data Femto = Femto+instance UnitPrefix Femto where+ multiplier _ = 1e-15+instance Show Femto where+ show _ = "f"++femto :: unit -> Femto :@ unit+femto = (Femto :@)++-- | 10^-18+data Atto = Atto+instance UnitPrefix Atto where+ multiplier _ = 1e-18+instance Show Atto where+ show _ = "a"++atto :: unit -> Atto :@ unit+atto = (Atto :@)++-- | 10^-21+data Zepto = Zepto+instance UnitPrefix Zepto where+ multiplier _ = 1e-21+instance Show Zepto where+ show _ = "z"++zepto :: unit -> Zepto :@ unit+zepto = (Zepto :@)++-- | 10^-24+data Yocto = Yocto+instance UnitPrefix Yocto where+ multiplier _ = 1e-24+instance Show Yocto where+ show _ = "y"++yocto :: unit -> Yocto :@ unit+yocto = (Yocto :@)
+ Data/Dimensions/SI/Types.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.SI.Types+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module defines type synonyms for SI units.+-----------------------------------------------------------------------------++module Data.Dimensions.SI.Types where++import Data.Dimensions+import Data.Dimensions.SI.Units++type Length = MkDim Meter+type Mass = MkDim Gram+type Time = MkDim Second+type Current = MkDim Ampere+type Temperature = MkDim Kelvin+type Quantity = MkDim Mole+type Luminosity = MkDim Candela++type Area = Length %^ Two+type Volume = Length %^ Three+type Velocity = Length %/ Time+type Acceleration = Length %/ (Time %^ Two)+type Wavenumber = Length %^ MOne+type Density = Mass %/ Volume+type SurfaceDensity = Mass %/ Area+type SpecificVolume = Volume %/ Mass+type CurrentDensity = Current %/ Area+type MagneticStrength = Current %/ Length+type Concentration = Quantity %/ Volume+type Luminance = Luminosity %/ Area++type Frequency = MkDim Hertz+type Force = MkDim Newton+type Pressure = MkDim Pascal+type Energy = MkDim Joule+type Power = MkDim Watt+type Charge = MkDim Coulomb+type ElectricPotential = MkDim Volt+type Capacitance = MkDim Farad+type Resistance = MkDim Ohm+type Conductance = MkDim Siemens+type MagneticFlux = MkDim Weber+type MagneticFluxDensity = MkDim Tesla+type Inductance = MkDim Henry+type LuminousFlux = MkDim Lumen+type Illuminance = MkDim Lux+type Kerma = MkDim Gray+type CatalyticActivity = MkDim Katal++type Momentum = Mass %* Velocity
+ Data/Dimensions/SI/Units.hs view
@@ -0,0 +1,179 @@+{-# LANGUAGE TypeFamilies, TypeOperators #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.SI.Units+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module exports unit definitions according to the SI system of units.+-- The definitions were taken from here: <http://www.bipm.org/en/si/>.+--+-- There is one deviation from the definition at that site: To work better+-- with prefixes, the unit of mass is 'Gram'.+-----------------------------------------------------------------------------++module Data.Dimensions.SI.Units where++import Data.Dimensions++data Meter = Meter+instance Unit Meter where+ type BaseUnit Meter = Canonical+instance Show Meter where+ show _ = "m"++data Gram = Gram+instance Unit Gram where+ type BaseUnit Gram = Canonical+instance Show Gram where+ show _ = "g"++data Second = Second+instance Unit Second where+ type BaseUnit Second = Canonical+instance Show Second where+ show _ = "s"++data Ampere = Ampere+instance Unit Ampere where+ type BaseUnit Ampere = Canonical+instance Show Ampere where+ show _ = "A"++data Kelvin = Kelvin+instance Unit Kelvin where+ type BaseUnit Kelvin = Canonical+instance Show Kelvin where+ show _ = "K"++data Mole = Mole+instance Unit Mole where+ type BaseUnit Mole = Canonical+instance Show Mole where+ show _ = "mol"++data Candela = Candela+instance Unit Candela where+ type BaseUnit Candela = Canonical+instance Show Candela where+ show _ = "cd"++data Hertz = Hertz+instance Unit Hertz where+ type BaseUnit Hertz = Number :/ Second+instance Show Hertz where+ show _ = "Hz"++data Newton = Newton+instance Unit Newton where+ type BaseUnit Newton = Meter :* Gram :/ (Second :^ Two)+ conversionRatio _ = 1000+instance Show Newton where+ show _ = "N"++data Pascal = Pascal+instance Unit Pascal where+ type BaseUnit Pascal = Newton :/ (Meter :^ Two)+instance Show Pascal where+ show _ = "Pa"++data Joule = Joule+instance Unit Joule where+ type BaseUnit Joule = Newton :* Meter+instance Show Joule where+ show _ = "J"++data Watt = Watt+instance Unit Watt where+ type BaseUnit Watt = Joule :/ Second+instance Show Watt where+ show _ = "W"++data Coulomb = Coulomb+instance Unit Coulomb where+ type BaseUnit Coulomb = Second :* Ampere+instance Show Coulomb where+ show _ = "C"++data Volt = Volt+instance Unit Volt where+ type BaseUnit Volt = Watt :/ Ampere+instance Show Volt where+ show _ = "V"++data Farad = Farad+instance Unit Farad where+ type BaseUnit Farad = Coulomb :/ Volt+instance Show Farad where+ show _ = "F"++data Ohm = Ohm+instance Unit Ohm where+ type BaseUnit Ohm = Volt :/ Ampere+instance Show Ohm where+ show _ = "Ω"++data Siemens = Siemens+instance Unit Siemens where+ type BaseUnit Siemens = Ampere :/ Volt+instance Show Siemens where+ show _ = "S"++data Weber = Weber+instance Unit Weber where+ type BaseUnit Weber = Volt :* Second+instance Show Weber where+ show _ = "Wb"++data Tesla = Tesla+instance Unit Tesla where+ type BaseUnit Tesla = Weber :/ (Meter :^ Two)+instance Show Tesla where+ show _ = "T"++data Henry = Henry+instance Unit Henry where+ type BaseUnit Henry = Weber :/ Ampere+instance Show Henry where+ show _ = "H"++data Lumen = Lumen+instance Unit Lumen where+ type BaseUnit Lumen = Candela+instance Show Lumen where+ show _ = "lm"++data Lux = Lux+instance Unit Lux where+ type BaseUnit Lux = Lumen :/ (Meter :^ Two)+instance Show Lux where+ show _ = "lx"++data Becquerel = Becquerel+instance Unit Becquerel where+ type BaseUnit Becquerel = Number :/ Second+instance Show Becquerel where+ show _ = "Bq"++data Gray = Gray+instance Unit Gray where+ type BaseUnit Gray = (Meter :^ Two) :/ (Second :^ Two)+instance Show Gray where+ show _ = "Gy"++data Sievert = Sievert+instance Unit Sievert where+ type BaseUnit Sievert = (Meter :^ Two) :/ (Second :^ Two)+instance Show Sievert where+ show _ = "Sv"++data Katal = Katal+instance Unit Katal where+ type BaseUnit Katal = Mole :/ Second+instance Show Katal where+ show _ = "kat"+
+ Data/Dimensions/Show.hs view
@@ -0,0 +1,73 @@+{-# LANGUAGE PolyKinds, DataKinds, TypeOperators, FlexibleInstances,+ ScopedTypeVariables #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.Show+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module defines only a 'Show' instance for dimensioned quantities.+-- The Show instance prints out the number stored internally with its canonical+-- units.+-----------------------------------------------------------------------------++module Data.Dimensions.Show () where++import Data.Proxy (Proxy(..))+import Data.List+import Data.Singletons (Sing, sing, SingI)++import Data.Dimensions.DimSpec+import Data.Dimensions.Dim+import Data.Dimensions.Z++class ShowDimSpec (dims :: [DimSpec *]) where+ showDims :: Proxy dims -> ([String], [String])++instance ShowDimSpec '[] where+ showDims _ = ([], [])++instance (ShowDimSpec rest, Show unit, SingI z)+ => ShowDimSpec (D unit z ': rest) where+ showDims _ =+ let (nums, denoms) = showDims (Proxy :: Proxy rest)+ baseStr = show (undefined :: unit)+ power = szToInt (sing :: Sing z)+ abs_power = abs power+ str = if abs_power == 1+ then baseStr+ else baseStr ++ "^" ++ (show abs_power) in+ case compare power 0 of+ LT -> (nums, str : denoms)+ EQ -> (nums, denoms)+ GT -> (str : nums, denoms)++showDimSpec :: ShowDimSpec dimspec => Proxy dimspec -> String+showDimSpec p+ = let (nums, denoms) = mapPair (build_string . sort) $ showDims p in+ case (length nums, length denoms) of+ (0, 0) -> ""+ (_, 0) -> " " ++ nums+ (0, _) -> " 1/" ++ denoms+ (_, _) -> " " ++ nums ++ "/" ++ denoms+ where+ mapPair :: (a -> b) -> (a, a) -> (b, b)+ mapPair f (x, y) = (f x, f y)++ build_string :: [String] -> String+ build_string [] = ""+ build_string [s] = s+ build_string s = "(" ++ build_string_helper s ++ ")"++ build_string_helper :: [String] -> String+ build_string_helper [] = ""+ build_string_helper [s] = s+ build_string_helper (h:t) = h ++ " * " ++ build_string_helper t++instance (ShowDimSpec dims, Show n) => Show (Dim n dims) where+ show (Dim d) = (show d ++ showDimSpec (Proxy :: Proxy dims))
+ Data/Dimensions/UnitCombinators.hs view
@@ -0,0 +1,72 @@+{- Data/Dimensions/UnitCombinators.hs++ The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file defines combinators to build more complex units from simpler ones.+-}++{-# LANGUAGE TypeOperators, TypeFamilies, UndecidableInstances,+ ScopedTypeVariables, DataKinds, FlexibleInstances #-}++module Data.Dimensions.UnitCombinators where++import Data.Singletons ( Sing, SingI, sing )++import Data.Dimensions.Units+import Data.Dimensions.DimSpec+import Data.Dimensions.Z++infixl 7 :*+-- | Multiply two units to get another unit.+-- For example: @type MetersSquared = Meter :* Meter@+data u1 :* u2 = u1 :* u2++instance (Unit u1, Unit u2) => Unit (u1 :* u2) where++ -- we override the default conversion lookup behavior+ type BaseUnit (u1 :* u2) = Canonical+ conversionRatio _ = undefined -- this should never be called++ type DimSpecsOf (u1 :* u2) = (DimSpecsOf u1) @+ (DimSpecsOf u2)+ canonicalConvRatio _ = canonicalConvRatio (undefined :: u1) *+ canonicalConvRatio (undefined :: u2)++infixl 7 :/+-- | Divide two units to get another unit+data u1 :/ u2 = u1 :/ u2++instance (Unit u1, Unit u2) => Unit (u1 :/ u2) where+ type BaseUnit (u1 :/ u2) = Canonical+ conversionRatio _ = undefined -- this should never be called+ type DimSpecsOf (u1 :/ u2) = (DimSpecsOf u1) @- (DimSpecsOf u2)+ canonicalConvRatio _ = canonicalConvRatio (undefined :: u1) /+ canonicalConvRatio (undefined :: u2)++infixr 8 :^+-- | Raise a unit to a power, known at compile time+data unit :^ (power :: Z) = unit :^ Sing power++instance (Unit unit, SingI power) => Unit (unit :^ power) where+ type BaseUnit (unit :^ power) = Canonical+ conversionRatio _ = undefined++ type DimSpecsOf (unit :^ power) = (DimSpecsOf unit) @* power+ canonicalConvRatio _ = canonicalConvRatio (undefined :: unit) ^^ (szToInt (sing :: Sing power))++infixr 9 :@+-- | Multiply a conversion ratio by some constant. Used for defining prefixes.+data prefix :@ unit = prefix :@ unit++-- | A class for user-defined prefixes+class UnitPrefix prefix where+ -- | This should return the desired multiplier for the prefix being defined.+ -- This function must /not/ inspect its argument.+ multiplier :: prefix -> Double++instance ( CheckCanonical unit ~ False+ , Unit unit+ , UnitPrefix prefix ) => Unit (prefix :@ unit) where+ type BaseUnit (prefix :@ unit) = unit+ conversionRatio _ = multiplier (undefined :: prefix)
+ Data/Dimensions/Units.hs view
@@ -0,0 +1,112 @@+{- Data/Dimensions/Units.hs++ The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file defines the class Unit, which is needed for+ user-defined units.+-}++{-# LANGUAGE TypeFamilies, DataKinds, DefaultSignatures, MultiParamTypeClasses,+ ConstraintKinds, UndecidableInstances, FlexibleContexts,+ FlexibleInstances, ScopedTypeVariables #-}++module Data.Dimensions.Units where++import Data.Dimensions.Z+import Data.Dimensions.DimSpec+import Data.Dimensions.Dim+import Data.Type.Bool++-- | Dummy type use just to label canonical units. It does /not/ have a+-- 'Unit' instance.+data Canonical++-- | Class of units. Make an instance of this class to define a new unit.+class Unit unit where+ -- | The base unit of this unit: what this unit is defined in terms of.+ -- For units that are not defined in terms of anything else, the base unit+ -- should be 'Canonical'.+ type BaseUnit unit :: *++ -- | The conversion ratio /from/ the base unit /to/ this unit.+ -- If left out, a conversion ratio of 1 is assumed.+ --+ -- For example:+ --+ -- > instance Unit Foot where+ -- > type BaseUnit Foot = Meter+ -- > conversionRatio _ = 0.3048+ --+ -- Implementations should /never/ examine their argument!+ conversionRatio :: unit -> Double++ -- | The internal list of dimensions for a dimensioned quantity built from+ -- this unit.+ type DimSpecsOf unit :: [DimSpec *]+ type DimSpecsOf unit = If (IsCanonical unit)+ '[D unit One]+ (DimSpecsOf (BaseUnit unit))++ -- if unspecified, assume a conversion ratio of 1+ conversionRatio _ = 1++ -- | Compute the conversion from the underlying canonical unit to+ -- this one. A default is provided that multiplies together the ratios+ -- of all units between this one and the canonical one.+ canonicalConvRatio :: unit -> Double+ default canonicalConvRatio :: BaseHasConvRatio unit => unit -> Double+ canonicalConvRatio u = conversionRatio u * baseUnitRatio u++-- Abbreviation for creating a Dim (defined here to avoid a module cycle)++-- | Make a dimensioned quantity type capable of storing a value of a given+-- unit. This uses a 'Double' for storage of the value. For example:+--+-- > type Length = MkDim Meter+type MkDim unit = Dim Double (DimSpecsOf unit)++-- | Make a dimensioned quantity with a custom numerical type.+type MkGenDim n unit = Dim n (DimSpecsOf unit)++-- | Is this unit a canonical unit?+type IsCanonical (unit :: *) = CheckCanonical (BaseUnit unit)++-- | Is the argument the special datatype 'Canonical'?+type family CheckCanonical (base_unit :: *) :: Bool where+ CheckCanonical Canonical = True+ CheckCanonical unit = False++{- I want to say this. But type families are *eager* so I have to write+ it another way.+type family CanonicalUnit (unit :: *) where+ CanonicalUnit unit+ = If (IsCanonical unit) unit (CanonicalUnit (BaseUnit unit))+-}++-- | Get the canonical unit from a given unit.+-- For example: @CanonicalUnit Foot = Meter@+type CanonicalUnit (unit :: *) = CanonicalUnit' (BaseUnit unit) unit++-- | Helper function in 'CanonicalUnit'+type family CanonicalUnit' (base_unit :: *) (unit :: *) :: * where+ CanonicalUnit' Canonical unit = unit+ CanonicalUnit' base unit = CanonicalUnit' (BaseUnit base) base++-- | Essentially, a constraint that checks if a conversion ratio can be+-- calculated for a @BaseUnit@ of a unit.+type BaseHasConvRatio unit = HasConvRatio (IsCanonical unit) unit++-- | This is like 'Unit', but deals with 'Canonical'. It is necessary+-- to be able to define 'canonicalConvRatio' in the right way.+class is_canonical ~ IsCanonical unit+ => HasConvRatio (is_canonical :: Bool) (unit :: *) where+ baseUnitRatio :: unit -> Double+instance True ~ IsCanonical canonical_unit+ => HasConvRatio True canonical_unit where+ baseUnitRatio _ = 1+instance ( False ~ IsCanonical noncanonical_unit+ , Unit (BaseUnit noncanonical_unit) )+ => HasConvRatio False noncanonical_unit where+ baseUnitRatio _ = canonicalConvRatio (undefined :: BaseUnit noncanonical_unit)
+ Data/Dimensions/Unsafe.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE ExplicitNamespaces #-}++-----------------------------------------------------------------------------+-- |+-- Module : Data.Dimensions.Unsafe+-- Copyright : (C) 2013 Richard Eisenberg+-- License : BSD-style (see LICENSE)+-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)+-- Stability : experimental+-- Portability : non-portable+--+-- This module exports the constructor of the 'Dim' type. This allows you+-- to write dimension-unsafe code. Use at your peril.+-----------------------------------------------------------------------------++module Data.Dimensions.Unsafe (+ -- * The 'Dim' type+ Dim(..),+ ) where++import Data.Dimensions.Dim+
+ Data/Dimensions/Z.hs view
@@ -0,0 +1,148 @@+{- Data/Dimensions/Z.hs+ + The units Package+ Copyright (c) 2013 Richard Eisenberg+ eir@cis.upenn.edu++ This file contains a definition of integers at the type-level, in terms+ of a promoted datatype 'Z'.+-}++{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators, UndecidableInstances,+ GADTs, PolyKinds, TemplateHaskell, ScopedTypeVariables,+ EmptyCase #-}+{-# OPTIONS_GHC -fno-warn-missing-signatures #-}++-- | This module defines a datatype and operations to represent type-level+-- integers. Though it's defined as part of the units package, it may be+-- useful beyond dimensional analysis. If you have a compelling non-units+-- use of this package, please let me (Richard, @eir@ at @cis.upenn.edu@)+-- know.++module Data.Dimensions.Z where++import Data.Singletons.TH++-- | The datatype for type-level integers.+$(singletons [d| data Z = Zero | S Z | P Z deriving Eq |])++-- | Convert a 'Z' to an 'Int'+zToInt :: Z -> Int+zToInt Zero = 0+zToInt (S z) = zToInt z + 1+zToInt (P z) = zToInt z - 1++-- | Add one to an integer+type family Succ (z :: Z) :: Z where+ Succ Zero = S Zero+ Succ (P z) = z+ Succ (S z) = S (S z)++-- | Subtract one from an integer+type family Pred (z :: Z) :: Z where+ Pred Zero = P Zero+ Pred (P z) = P (P z)+ Pred (S z) = z++infixl 6 #++-- | Add two integers+type family (a :: Z) #+ (b :: Z) :: Z where+ Zero #+ z = z+ (S z1) #+ (S z2) = S (S (z1 #+ z2))+ (S z1) #+ Zero = S z1+ (S z1) #+ (P z2) = z1 #+ z2+ (P z1) #+ (S z2) = z1 #+ z2+ (P z1) #+ Zero = P z1+ (P z1) #+ (P z2) = P (P (z1 #+ z2))++infixl 6 #-+-- | Subtract two integers+type family (a :: Z) #- (b :: Z) :: Z where+ z #- Zero = z+ (S z1) #- (S z2) = z1 #- z2+ Zero #- (S z2) = P (Zero #- z2)+ (P z1) #- (S z2) = P (P (z1 #- z2))+ (S z1) #- (P z2) = S (S (z1 #- z2))+ Zero #- (P z2) = S (Zero #- z2)+ (P z1) #- (P z2) = z1 #- z2++infixl 7 #*+-- | Multiply two integers+type family (a :: Z) #* (b :: Z) :: Z where+ Zero #* z = Zero+ (S z1) #* z2 = (z1 #* z2) #+ z2+ (P z1) #* z2 = (z1 #* z2) #- z2++-- | Negate an integer+type family NegZ (z :: Z) :: Z where+ NegZ Zero = Zero+ NegZ (S z) = P (NegZ z)+ NegZ (P z) = S (NegZ z)++-- | Divide two integers+type family (a :: Z) #/ (b :: Z) :: Z where+ Zero #/ b = Zero+ a #/ (P b') = NegZ (a #/ (NegZ (P b')))+ a #/ b = ZDiv b b a++-- | Helper function for division+type family ZDiv (counter :: Z) (n :: Z) (z :: Z) :: Z where+ ZDiv One n (S z') = S (z' #/ n)+ ZDiv One n (P z') = P (z' #/ n)+ ZDiv (S count') n (S z') = ZDiv count' n z'+ ZDiv (S count') n (P z') = ZDiv count' n z'++-- | Less-than comparison+type family (a :: Z) < (b :: Z) :: Bool where+ Zero < Zero = False+ Zero < (S n) = True+ Zero < (P n) = False+ (S n) < Zero = False+ (S n) < (S n') = n < n'+ (S n) < (P n') = False+ (P n) < Zero = True+ (P n) < (S n') = True+ (P n) < (P n') = n < n'++type One = S Zero+type Two = S One+type Three = S Two+type Four = S Three+type Five = S Four++type MOne = P Zero+type MTwo = P MOne+type MThree = P MTwo+type MFour = P MThree+type MFive = P MFour++-- | This is the singleton value representing @Zero@ at the term level and+-- at the type level, simultaneously. Used for raising units to powers.+pZero = SZero+pOne = SS pZero+pTwo = SS pOne+pThree = SS pTwo+pFour = SS pThree+pFive = SS pFour++pMOne = SP pZero+pMTwo = SP pMOne+pMThree = SP pMTwo+pMFour = SP pMThree+pMFive = SP pMFour++-- | Add one to a singleton @Z@.+pSucc :: Sing z -> Sing (Succ z)+pSucc SZero = pOne+pSucc (SS z') = SS (SS z')+pSucc (SP z') = z'++-- | Subtract one from a singleton @Z@.+pPred :: Sing z -> Sing (Pred z)+pPred SZero = pMOne+pPred (SS z') = z'+pPred (SP z') = SP (SP z')++-- | Convert a singleton @Z@ to an @Int@.+szToInt :: Sing (z :: Z) -> Int+szToInt = zToInt . fromSing
README.md view
@@ -9,18 +9,6 @@ such as Meter and Foot. When extracting a number from a dimensioned quantity, the desired unit must be specified, and the value is converted into that unit. -Limitations:-- The _units_ package does not easily allow users to write code polymorphic- in the chosen units. For example, a `sum` function that adds together a- homogeneous list of dimensioned quantities is not straightforward. The- package exports its internals to allow clients to try to get these working,- but it is generally hard to do. However, monomorphic functions are easy.--- The _units_ package is not generalized over number representation: it forces- client code to use `Double`. It wouldn't be hard to generalize, though, but- it would add a fair amount of extra cruft here and there. Shout (to- `eir@cis.upenn.edu`) if this is important to you.- User contributions ------------------ @@ -47,6 +35,19 @@ for you to build your own set of units and operate with them. All modules implicitly depend on this one. + - __`Data.Dimensions.Poly`__++ This module exports some more definitions that may be useful when writing+ functions polymorphic over the choice of dimension. These functions are+ sometimes challenging (or perhaps impossible) to write, as the system is+ designed more with _monomorphic_ use than polymorphic use.++ - __`Data.Dimensions.Unsafe`__++ This module exports the constructor for the central datatype that stores+ dimensioned quantities. With this constructor, you can arbitrarily change+ units! Use at your peril.+ - __`Data.Dimensions.Show`__ This module defines a `Show` instance for dimensioned quantities, printing@@ -55,22 +56,28 @@ - __`Data.Dimensions.SI`__ - This module exports unit definitions for the [SI][] system of units.+ This module exports unit definitions for the [SI][] system of units,+ re-exporting the three modules below. [SI]: http://en.wikipedia.org/wiki/International_System_of_Units-- - __`Data.Dimensions.SI.Prefixes`__+ + - __`Data.Dimensions.SI.Units`__ - This module exports the SI prefixes. Note that this does *not* depend- on `Data.Dimensions.SI` -- you can use these prefixes with any system of- units.+ This module exports only the SI units, such as `Meter` and `Ampere`. - __`Data.Dimensions.SI.Types`__ - This module exports several useful types for use with the SI package,+ This module exports several useful types for use with the SI.Units module, which it depends on. For example, `Length` is the type of dimensioned quantities made with `Meter`s. + - __`Data.Dimensions.SI.Prefixes`__++ This module exports the SI prefixes. Note that this does *not* depend on+ any of the other SI modules -- you can use these prefixes with any system+ of units.++ Examples ======== @@ -212,9 +219,6 @@ roomSize' :: Area1 roomSize' = 100 % (Meter :* Meter) -These operations have no defined inverses, though I don't think they would be-hard to define. Shout if you need that functionality.- Note that addition and subtraction on units does not make physical sense, so those operations are not provided. @@ -230,12 +234,13 @@ happen that the inferred type of your expression and the given type of your function may not exactly match up. This is because dimensioned quantities have a looser notion of type equality than Haskell does. For example, "meter *-second" should be the same as "second * meter", even those these are in+second" should be the same as "second * meter", even though these are in different order. The `dim` function checks (at compile time) to make sure its input type and output type represent the same underlying dimension and then-performs a cast from one to the other. When providing type annotations, it is-good practice to start your function with a `dim $` to prevent the possibility-of type errors. For example, say we redefine velocity a different way:+performs a cast from one to the other. This cast is completely free at+runtime. When providing type annotations, it is good practice to start your+function with a `dim $` to prevent the possibility of type errors. For+example, say we redefine velocity a different way: type Velocity3 = Scalar %/ Time %* Length addVels :: Velocity1 -> Velocity1 -> Velocity3
− src/Data/Dimensions.hs
@@ -1,140 +0,0 @@-{- Data/Dimensions.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file gathers and exports all user-visible pieces of the units package.- It also defines the main creators and consumers of dimensioned objects.-- This package declares many closely-related types. The following naming- conventions should be helpful:-- Prefix Target type/kind- ------------------------- # Z- $ DimSpec *- @ [DimSpec *]- @@ [DimSpec *], where the arguments are ordered similarly- % Dim (at the type level)- . Dim (at the term level)- : units, at both type and term levels--}--{-# LANGUAGE ExplicitNamespaces, DataKinds, FlexibleInstances, TypeFamilies,- TypeOperators, ConstraintKinds #-}--{-| The units package is a framework for strongly-typed dimensional analysis.- This haddock documentation is generally /not/ enough to be able to use this- package effectively. Please see the readme at- <https://github.com/goldfirere/units/blob/master/README.md>.-- Some of the types below refer to declarations that are not exported and- not documented here. This is because Haddock does not allow finely-tuned- abstraction in documentation. (In particular, right-hand sides of type - synonym declarations are always included.) If a symbol is not exported,- you do /not/ need to know anything about it to use this package.-- The type @Dim@, which is not exported, is the type used internally to- represent dimensioned quantities.-- Though it doesn't appear here, @Scalar@ is an instance of @Num@, and- generally has all the numeric instances that @Double@ has.--}--module Data.Dimensions (- -- * Term-level combinators- (.+), (.-), (.*), (./), (.^), (*.),- (.<), (.>), (.<=), (.>=), dimEq, dimNeq,- nthRoot, dimSqrt, dimCubeRoot,- unity, zero, dim,- dimIn, (#), dimOf, (%),-- -- * Type-level unit combinators- (:*)(..), (:/)(..), (:^)(..), (:@)(..),- UnitPrefix(..),-- -- * Type-level dimensioned-quantity combinators- type (%*), type (%/), type (%^),-- -- * Creating new units- Unit(type BaseUnit, conversionRatio), MkDim, Canonical,-- -- * Scalars, the only built-in unit- Number(..), Scalar, scalar,-- -- * Type-level integers- Z(..), Succ, Pred, type (#+), type (#-), type (#*), type (#/), NegZ,-- -- ** Synonyms for small numbers- One, Two, Three, Four, Five, MOne, MTwo, MThree, MFour, MFive,-- -- ** Term-level singletons- pZero, pOne, pTwo, pThree, pFour, pFive,- pMOne, pMTwo, pMThree, pMFour, pMFive,- pSucc, pPred-- ) where--import Data.Dimensions.Z-import Data.Dimensions.Dim-import Data.Dimensions.DimSpec-import Data.Dimensions.Units-import Data.Dimensions.UnitCombinators---- | Extracts a @Double@ from a dimensioned quantity, expressed in--- the given unit. For example:------ > inMeters :: Length -> Double--- > inMeters x = dimIn x Meter-dimIn :: Unit unit => MkDim (CanonicalUnit unit) -> unit -> Double-dimIn (Dim val) u = val / canonicalConvRatio u--infix 5 #--- | Infix synonym for 'dimIn'-(#) :: Unit unit => MkDim (CanonicalUnit unit) -> unit -> Double-(#) = dimIn---- | Creates a dimensioned quantity in the given unit. For example:------ > height :: Length--- > height = dimOf 2.0 Meter-dimOf :: Unit unit => Double -> unit -> MkDim (CanonicalUnit unit)-dimOf d u = Dim (d * canonicalConvRatio u)--infix 9 %--- | Infix synonym for 'dimOf'-(%) :: Unit unit => Double -> unit -> MkDim (CanonicalUnit unit)-(%) = dimOf---- | The number 1, expressed as a unitless dimensioned quantity.-unity :: Dim '[]-unity = Dim 1---- | The number 0, expressed as a polymorphic dimensioned quantity.--- The polymorphism allows it to be added to any dimensioned quantity--- without fuss.-zero :: Dim '[DAny]-zero = Dim 0---- | Dimension-safe cast. See the README for more info.-dim :: (d @~ e) => Dim d -> Dim e-dim (Dim x) = Dim x------------------------------------------------------------------- "Number" unit ------------------------------------------------------------------------------------------------------------- | The unit for unitless dimensioned quantities-data Number = Number -- the unit for unadorned numbers-instance Unit Number where- type BaseUnit Number = Canonical- type DimSpecsOf Number = '[]---- | The type of unitless dimensioned quantities--- This is an instance of @Num@, though Haddock doesn't show it.-type Scalar = MkDim Number---- | Convert a Double into a unitless dimensioned quantity-scalar :: Double -> Dim '[]-scalar = Dim
− src/Data/Dimensions/Dim.hs
@@ -1,148 +0,0 @@-{- Data/Dimensions.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file defines the Dim type and operations on that type.--}--{-# LANGUAGE TypeFamilies, TypeOperators, DataKinds, UndecidableInstances,- ConstraintKinds, StandaloneDeriving, GeneralizedNewtypeDeriving,- FlexibleInstances #-}--module Data.Dimensions.Dim where--import GHC.TypeLits ( Sing )--import Data.Dimensions.DimSpec-import Data.Dimensions.Z------------------------------------------------------------------- Internal ------------------------------------------------------------------------------------------------------------------ | Dim adds a dimensional annotation to a Double. This is the--- representation for all dimensioned quantities.-newtype Dim (a :: [DimSpec *]) = Dim Double------------------------------------------------------------------- User-facing -------------------------------------------------------------------------------------------------------------infixl 6 .+--- | Add two compatible dimensioned quantities-(.+) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Dim (ChooseFrom d1 d2)-(Dim a) .+ (Dim b) = Dim (a + b)--infixl 6 .---- | Subtract two compatible dimensioned quantities-(.-) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Dim (ChooseFrom d1 d2)-(Dim a) .- (Dim b) = Dim (a - b)--infixl 7 .*--- | Multiply two dimensioned quantities-(.*) :: Dim a -> Dim b -> Dim (Normalize (a @+ b))-(Dim a) .* (Dim b) = Dim (a * b)--infixl 7 ./--- | Divide two dimensioned quantities-(./) :: Dim a -> Dim b -> Dim (Normalize (a @- b))-(Dim a) ./ (Dim b) = Dim (a / b)--infixr 8 .^--- | Raise a dimensioned quantity to a power known at compile time-(.^) :: Dim a -> Sing z -> Dim (a @* z)-(Dim a) .^ sz = Dim (a ^^ szToInt sz)---- | Take the n'th root of a dimensioned quantity, where n is known at compile--- time-nthRoot :: (Zero < z) ~ True => Sing z -> Dim a -> Dim (a @/ z)-nthRoot sz (Dim a) = Dim (a ** (1.0 / (fromIntegral $ szToInt sz)))--infix 4 .<--- | Check if one dimensioned quantity is less than a compatible one-(.<) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Bool-(Dim a) .< (Dim b) = a < b--infix 4 .>--- | Check if one dimensioned quantity is greater than a compatible one-(.>) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Bool-(Dim a) .> (Dim b) = a > b--infix 4 .<=--- | Check if one dimensioned quantity is less than or equal to a compatible one-(.<=) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Bool-(Dim a) .<= (Dim b) = a <= b--infix 4 .>=--- | Check if one dimensioned quantity is greater than or equal to a compatible one-(.>=) :: (d1 @~ d2) => Dim d1 -> Dim d2 -> Bool-(Dim a) .>= (Dim b) = a >= b---- | Compare two compatible dimensioned quantities for equality-dimEq :: (d0 @~ d1, d0 @~ d2) => Dim d0 -- ^ If the difference between the next- -- two arguments are less than this - -- amount, they are considered equal- -> Dim d1 -> Dim d2 -> Bool-dimEq (Dim epsilon) (Dim a) (Dim b) = abs(a-b) < epsilon---- | Compare two compatible dimensioned quantities for inequality-dimNeq :: (d0 @~ d1, d0 @~ d2) => Dim d0 -- ^ If the difference between the next- -- two arguments are less than this - -- amount, they are considered equal- -> Dim d1 -> Dim d2 -> Bool-dimNeq (Dim epsilon) (Dim a) (Dim b) = abs(a-b) >= epsilon---- | Square a dimensioned quantity-dimSqr :: Dim a -> Dim (Normalize (a @+ a))-dimSqr x = x .* x---- | Take the square root of a dimensioned quantity-dimSqrt :: Dim a -> Dim (a @/ Two)-dimSqrt = nthRoot pTwo---- | Take the cube root of a dimensioned quantity-dimCubeRoot :: Dim a -> Dim (a @/ Three)-dimCubeRoot = nthRoot pThree--infixl 7 *.--- | Multiply a dimensioned quantity by a scalar @Double@-(*.) :: Double -> Dim a -> Dim a-a *. (Dim b) = Dim (a * b)------------------------------------------------------------------- Instances ---------------------------------------------------------------------------------------------------------------deriving instance Eq (Dim '[])-deriving instance Ord (Dim '[])-deriving instance Num (Dim '[])-deriving instance Real (Dim '[])-deriving instance Fractional (Dim '[])-deriving instance Floating (Dim '[])-deriving instance RealFrac (Dim '[])-deriving instance RealFloat (Dim '[])------------------------------------------------------------------- Combinators -------------------------------------------------------------------------------------------------------------infixl 7 %*--- | Multiply two dimension types to produce a new one. For example:------ > type Velocity = Length %/ Time-type family (d1 :: *) %* (d2 :: *) :: *-type instance (Dim d1) %* (Dim d2) = Dim (d1 @+ d2)--infixl 7 %/--- | Divide two dimension types to produce a new one-type family (d1 :: *) %/ (d2 :: *) :: *-type instance (Dim d1) %/ (Dim d2) = Dim (d1 @- d2)--infixr 8 %^--- | Exponentiate a dimension type to an integer-type family (d :: *) %^ (z :: Z) :: *-type instance (Dim d) %^ z = Dim (d @* z)--
− src/Data/Dimensions/DimSpec.hs
@@ -1,192 +0,0 @@-{- Data/Dimensions/DimSpec.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file defines the DimSpec kind and operations over lists of DimSpecs--}--{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators, UndecidableInstances #-}--module Data.Dimensions.DimSpec where--import GHC.Exts (Constraint)-import Data.Dimensions.TypePrelude-import Data.Dimensions.Z---- | This will only be used at the kind level.--- It either holds a dimension with its exponent, or the special constant DAny,--- which can be any combination of dimensions at any exponents. It is used to--- represent multiplying by 0 somewhere.-data DimSpec star = D star Z | DAny---------------------------------------------------------------- Set-like operations ----------------------------------------------------------------------------------------------{--These functions are templates for type-level functions.-remove :: String -> [String] -> [String]-remove _ [] = []-remove s (h:t) = if s == h then t else h : remove s t--member :: String -> [String] -> Bool-member _ [] = False-member s (h:t) = s == h || member s t--extract :: String -> [String] -> ([String], Maybe String)-extract _ [] = ([], Nothing)-extract s (h:t) =- if s == h- then (t, Just s)- else let (resList, resVal) = extract s t in (h : resList, resVal)--reorder :: [String] -> [String] -> [String]-reorder x [] = x-reorder x (h:t) =- case extract h x of- (lst, Nothing) -> reorder lst t- (lst, Just elt) -> elt : (reorder lst t)--}--infix 4 $=--- | Do these DimSpecs represent the same dimension?-type family (a :: DimSpec *) $= (b :: DimSpec *) :: Bool where- (D n1 z1) $= (D n2 z2) = n1 :=: n2- DAny $= DAny = True- a $= b = False---- | @(Extract s lst)@ pulls the DimSpec that matches s out of lst, returning a--- diminished list and, possibly, the extracted DimSpec.------ @--- Extract A [A, B, C] ==> ([B, C], Just A--- Extract D [A, B, C] ==> ([A, B, C], Nothing)--- @-type family Extract (s :: DimSpec *)- (lst :: [DimSpec *])- :: ([DimSpec *], Maybe (DimSpec *)) where- Extract s '[] = '( '[], Nothing )- Extract s (h ': t) =- If (s $= h)- '(t, Just h)- '(h ': Fst (Extract s t), Snd (Extract s t))---- kind DimAnnotation = [DimSpec *]--- a list of DimSpecs forms a full annotation of a quantity's dimension---- | Reorders a to be the in the same order as b, putting entries not in b at the end------ @--- Reorder [A 1, B 2] [B 5, A 2] ==> [B 2, A 1]--- Reorder [A 1, B 2, C 3] [C 2, A 8] ==> [C 3, A 1, B 2]--- Reorder [A 1, B 2] [B 4, C 1, A 9] ==> [B 2, A 1]--- Reorder x x ==> x--- Reorder x [] ==> x--- Reorder [] x ==> []--- @-type family Reorder (a :: [DimSpec *]) (b :: [DimSpec *]) :: [DimSpec *] where- Reorder x '[] = x- Reorder x (h ': t) = Reorder' (Extract h x) t---- | Helper function in 'Reorder'-type family Reorder' (scrut :: ([DimSpec *], Maybe (DimSpec *)))- (t :: [DimSpec *])- :: [DimSpec *] where- Reorder' '(lst, Nothing) t = Reorder lst t- Reorder' '(lst, Just elt) t = elt ': (Reorder lst t)---- | Check if a @[DimSpec *]@ has a 'DAny' inside it-type family HasAny (lst :: [DimSpec *]) :: Bool where- HasAny '[] = False- HasAny (DAny ': t) = True- HasAny (h ': t) = HasAny t--infix 4 @~--- | Check if two @[DimSpec *]@s should be considered to be equal-type family (a :: [DimSpec *]) @~ (b :: [DimSpec *]) :: Constraint where- a @~ b = If (HasAny a :||: HasAny b)- (() :: Constraint)- (Normalize (Reorder a b) ~ Normalize b)---------------------------------------------------------------- Normalization ------------------------------------------------------------------------------------------------------- | Take a @[DimSpec *]@ and remove any @DimSpec@s with an exponent of 0-type family Normalize' (d :: [DimSpec *]) :: [DimSpec *] where- Normalize' '[] = '[]- Normalize' ((D n Zero) ': t) = Normalize' t- Normalize' (h ': t) = h ': Normalize' t---- | If a @[DimSpec *]@ has a 'DAny', collapse the whole list to one 'DAny'.--- Otherwise, normalize the list by removing exponents of 0.-type family Normalize (d :: [DimSpec *]) :: [DimSpec *] where- Normalize d = If (HasAny d) '[DAny] (Normalize' d)---- | Given two @[DimSpec *]@s, return the one that lacks a 'DAny', if there is one.-type family ChooseFrom (d1 :: [DimSpec *]) (d2 :: [DimSpec *]) :: [DimSpec *] where- ChooseFrom d d = Normalize d- ChooseFrom '[DAny] d2 = Normalize d2 -- common cases- ChooseFrom d1 '[DAny] = Normalize d1- ChooseFrom d1 d2 = Normalize (If (HasAny d1) d2 d1)---------------------------------------------------------------- Arithmetic --------------------------------------------------------------------------------------------------------infixl 6 @@+--- | Adds corresponding exponents in two dimension, assuming the lists are--- ordered similarly.-type family (a :: [DimSpec *]) @@+ (b :: [DimSpec *]) :: [DimSpec *] where- '[] @@+ b = b- a @@+ '[] = a- (DAny ': t1) @@+ b = '[DAny]- a @@+ (DAny ': t2) = '[DAny]- ((D name z1) ': t1) @@+ ((D name z2) ': t2) = (D name (z1 #+ z2)) ': (t1 @@+ t2)- a @@+ (h ': t) = h ': (a @@+ t)--infixl 6 @+--- | Adds corresponding exponents in two dimension-type family (a :: [DimSpec *]) @+ (b :: [DimSpec *]) :: [DimSpec *] where- a @+ b = (Reorder a b) @@+ b--infixl 6 @@---- | Subtract exponents in two dimensions, assuming the lists are ordered--- similarly.-type family (a :: [DimSpec *]) @@- (b :: [DimSpec *]) :: [DimSpec *] where- '[] @@- b = NegList b- a @@- '[] = a- (DAny ': t1) @@- b = '[DAny]- a @@- (DAny ': t2) = '[DAny]- ((D name z1) ': t1) @@- ((D name z2) ': t2) = (D name (z1 #- z2)) ': (t1 @@- t2)- a @@- (h ': t) = (NegDim h) ': (a @@- t)--infixl 6 @---- | Subtract exponents in two dimensions-type family (a :: [DimSpec *]) @- (b :: [DimSpec *]) :: [DimSpec *] where- a @- b = (Reorder a b) @@- b---- | negate a single @DimSpec@-type family NegDim (a :: DimSpec *) :: DimSpec * where- NegDim (D n z) = D n (NegZ z)- NegDim DAny = DAny---- | negate a list of @DimSpec@s-type family NegList (a :: [DimSpec *]) :: [DimSpec *] where- NegList '[] = '[]- NegList (h ': t) = (NegDim h ': (NegList t))--infixl 7 @*--- | Multiplication of the exponents in a dimension by a scalar-type family (base :: [DimSpec *]) @* (power :: Z) :: [DimSpec *] where- '[] @* power = '[]- ((D name num) ': t) @* power = (D name (num #* power)) ': (t @* power)- (DAny ': t) @* power = DAny ': (t @* power)--infixl 7 @/--- | Division of the exponents in a dimension by a scalar-type family (dims :: [DimSpec *]) @/ (z :: Z) :: [DimSpec *] where- '[] @/ z = '[]- ((D name num) ': t) @/ z = (D name (num #/ z)) ': (t @/ z)- (DAny ': t) @/ z = DAny ': (t @/ z)
− src/Data/Dimensions/Internal.hs
@@ -1,38 +0,0 @@-{- Data/Dimensions/Internal.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu--}--{-# LANGUAGE ExplicitNamespaces #-}--{-| This module gathers and exports all parts of the units package that might- be useful, even when going past the abstraction layer of the package.-- With the exports from this module, it is possible to perform unsafe- operations that do not respect the rules of dimensional analysis. Use with- caution.-- Additionally, no attempt will be made to keep the exports of this module- backward compatible.--}--module Data.Dimensions.Internal (- -- * The @Dim@ type- Dim(..),-- -- * Manipulating dimension specifications- DimSpec(..), type ($=), Extract, Reorder, HasAny, type (@~),- Normalize, ChooseFrom,-- type (@+), type (@-), NegDim, NegList, type (@*), type (@/),-- -- * Generally-useful type operations- Fst, Snd, If, (:&&:), (:||:), (:=:)-- ) where--import Data.Dimensions.Dim-import Data.Dimensions.TypePrelude-import Data.Dimensions.DimSpec
− src/Data/Dimensions/SI.hs
@@ -1,180 +0,0 @@-{- Data/Dimensions/SI.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This module defines the units from the SI system, as put forth here:- http://www.bipm.org/en/si/--}--{-# LANGUAGE TypeFamilies, TypeOperators #-}--{-| This module exports unit definitions according to the SI system of units.- The definitions were taken from here: <http://www.bipm.org/en/si/>.-- There is one deviation from the definition at that site: To work better- with prefixes, the unit of mass is 'Gram'.--}--module Data.Dimensions.SI where--import Data.Dimensions--data Meter = Meter-instance Unit Meter where- type BaseUnit Meter = Canonical-instance Show Meter where- show _ = "m"--data Gram = Gram-instance Unit Gram where- type BaseUnit Gram = Canonical-instance Show Gram where- show _ = "g"--data Second = Second-instance Unit Second where- type BaseUnit Second = Canonical-instance Show Second where- show _ = "s"--data Ampere = Ampere-instance Unit Ampere where- type BaseUnit Ampere = Canonical-instance Show Ampere where- show _ = "A"--data Kelvin = Kelvin-instance Unit Kelvin where- type BaseUnit Kelvin = Canonical-instance Show Kelvin where- show _ = "K"--data Mole = Mole-instance Unit Mole where- type BaseUnit Mole = Canonical-instance Show Mole where- show _ = "mol"--data Candela = Candela-instance Unit Candela where- type BaseUnit Candela = Canonical-instance Show Candela where- show _ = "cd"--data Hertz = Hertz-instance Unit Hertz where- type BaseUnit Hertz = Number :/ Second-instance Show Hertz where- show _ = "Hz"--data Newton = Newton-instance Unit Newton where- type BaseUnit Newton = Meter :* Gram :/ (Second :^ Two)- conversionRatio _ = 1000-instance Show Newton where- show _ = "N"--data Pascal = Pascal-instance Unit Pascal where- type BaseUnit Pascal = Newton :/ (Meter :^ Two)-instance Show Pascal where- show _ = "Pa"--data Joule = Joule-instance Unit Joule where- type BaseUnit Joule = Newton :* Meter-instance Show Joule where- show _ = "J"--data Watt = Watt-instance Unit Watt where- type BaseUnit Watt = Joule :/ Second-instance Show Watt where- show _ = "W"--data Coulomb = Coulomb-instance Unit Coulomb where- type BaseUnit Coulomb = Second :* Ampere-instance Show Coulomb where- show _ = "C"--data Volt = Volt-instance Unit Volt where- type BaseUnit Volt = Watt :/ Ampere-instance Show Volt where- show _ = "V"--data Farad = Farad-instance Unit Farad where- type BaseUnit Farad = Coulomb :/ Volt-instance Show Farad where- show _ = "F"--data Ohm = Ohm-instance Unit Ohm where- type BaseUnit Ohm = Volt :/ Ampere-instance Show Ohm where- show _ = "Ω"--data Siemens = Siemens-instance Unit Siemens where- type BaseUnit Siemens = Ampere :/ Volt-instance Show Siemens where- show _ = "S"--data Weber = Weber-instance Unit Weber where- type BaseUnit Weber = Volt :* Second-instance Show Weber where- show _ = "Wb"--data Tesla = Tesla-instance Unit Tesla where- type BaseUnit Tesla = Weber :/ (Meter :^ Two)-instance Show Tesla where- show _ = "T"--data Henry = Henry-instance Unit Henry where- type BaseUnit Henry = Weber :/ Ampere-instance Show Henry where- show _ = "H"--data Lumen = Lumen-instance Unit Lumen where- type BaseUnit Lumen = Candela-instance Show Lumen where- show _ = "lm"--data Lux = Lux-instance Unit Lux where- type BaseUnit Lux = Lumen :/ (Meter :^ Two)-instance Show Lux where- show _ = "lx"--data Becquerel = Becquerel-instance Unit Becquerel where- type BaseUnit Becquerel = Number :/ Second-instance Show Becquerel where- show _ = "Bq"--data Gray = Gray-instance Unit Gray where- type BaseUnit Gray = (Meter :^ Two) :/ (Second :^ Two)-instance Show Gray where- show _ = "Gy"--data Sievert = Sievert-instance Unit Sievert where- type BaseUnit Sievert = (Meter :^ Two) :/ (Second :^ Two)-instance Show Sievert where- show _ = "Sv"--data Katal = Katal-instance Unit Katal where- type BaseUnit Katal = Mole :/ Second-instance Show Katal where- show _ = "kat"-
− src/Data/Dimensions/SI/Prefixes.hs
@@ -1,217 +0,0 @@-{- Data/Dimensions/SI/Prefixes.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This module defines the prefixes from the SI system, as put forth here:- http://www.bipm.org/en/si/--}--{-# LANGUAGE TypeOperators #-}---- | Defines prefixes from the SI standard at <http://www.bipm.org/en/si/>--module Data.Dimensions.SI.Prefixes where--import Data.Dimensions---- | 10^1-data Deca = Deca-instance UnitPrefix Deca where- multiplier _ = 1e1-instance Show Deca where- show _ = "da"--deca :: unit -> Deca :@ unit-deca = (Deca :@)---- | 10^2-data Hecto = Hecto-instance UnitPrefix Hecto where- multiplier _ = 1e2-instance Show Hecto where- show _ = "h"--hecto :: unit -> Hecto :@ unit-hecto = (Hecto :@)---- | 10^3-data Kilo = Kilo-instance UnitPrefix Kilo where- multiplier _ = 1e3-instance Show Kilo where- show _ = "k"--kilo :: unit -> Kilo :@ unit-kilo = (Kilo :@)---- | 10^6-data Mega = Mega-instance UnitPrefix Mega where- multiplier _ = 1e6-instance Show Mega where- show _ = "M"--mega :: unit -> Mega :@ unit-mega = (Mega :@)---- | 10^9-data Giga = Giga-instance UnitPrefix Giga where- multiplier _ = 1e9-instance Show Giga where- show _ = "G"--giga :: unit -> Giga :@ unit-giga = (Giga :@)---- | 10^12-data Tera = Tera-instance UnitPrefix Tera where- multiplier _ = 1e12-instance Show Tera where- show _ = "T"--tera :: unit -> Tera :@ unit-tera = (Tera :@)---- | 10^15-data Peta = Peta-instance UnitPrefix Peta where- multiplier _ = 1e15-instance Show Peta where- show _ = "P"--peta :: unit -> Peta :@ unit-peta = (Peta :@)---- | 10^18-data Exa = Exa-instance UnitPrefix Exa where- multiplier _ = 1e18-instance Show Exa where- show _ = "E"--exa :: unit -> Exa :@ unit-exa = (Exa :@)---- | 10^21-data Zetta = Zetta-instance UnitPrefix Zetta where- multiplier _ = 1e21-instance Show Zetta where- show _ = "Z"--zetta :: unit -> Zetta :@ unit-zetta = (Zetta :@)---- | 10^24-data Yotta = Yotta-instance UnitPrefix Yotta where- multiplier _ = 1e24-instance Show Yotta where- show _ = "Y"--yotta :: unit -> Yotta :@ unit-yotta = (Yotta :@)---- | 10^-1-data Deci = Deci-instance UnitPrefix Deci where- multiplier _ = 1e-1-instance Show Deci where- show _ = "d"--deci :: unit -> Deci :@ unit-deci = (Deci :@)---- | 10^-2-data Centi = Centi-instance UnitPrefix Centi where- multiplier _ = 1e-2-instance Show Centi where- show _ = "c"--centi :: unit -> Centi :@ unit-centi = (Centi :@)---- | 10^-3-data Milli = Milli-instance UnitPrefix Milli where- multiplier _ = 1e-3-instance Show Milli where- show _ = "m"--milli :: unit -> Milli :@ unit-milli = (Milli :@)---- | 10^-6-data Micro = Micro-instance UnitPrefix Micro where- multiplier _ = 1e-6-instance Show Micro where- show _ = "μ"--micro :: unit -> Micro :@ unit-micro = (Micro :@)---- | 10^-9-data Nano = Nano-instance UnitPrefix Nano where- multiplier _ = 1e-9-instance Show Nano where- show _ = "n"--nano :: unit -> Nano :@ unit-nano = (Nano :@)---- | 10^-12-data Pico = Pico-instance UnitPrefix Pico where- multiplier _ = 1e-12-instance Show Pico where- show _ = "p"--pico :: unit -> Pico :@ unit-pico = (Pico :@)---- | 10^-15-data Femto = Femto-instance UnitPrefix Femto where- multiplier _ = 1e-15-instance Show Femto where- show _ = "f"--femto :: unit -> Femto :@ unit-femto = (Femto :@)---- | 10^-18-data Atto = Atto-instance UnitPrefix Atto where- multiplier _ = 1e-18-instance Show Atto where- show _ = "a"--atto :: unit -> Atto :@ unit-atto = (Atto :@)---- | 10^-21-data Zepto = Zepto-instance UnitPrefix Zepto where- multiplier _ = 1e-21-instance Show Zepto where- show _ = "z"--zepto :: unit -> Zepto :@ unit-zepto = (Zepto :@)---- | 10^-24-data Yocto = Yocto-instance UnitPrefix Yocto where- multiplier _ = 1e-24-instance Show Yocto where- show _ = "y"--yocto :: unit -> Yocto :@ unit-yocto = (Yocto :@)
− src/Data/Dimensions/SI/Types.hs
@@ -1,56 +0,0 @@-{- Data/Dimensions/SI/Types.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu--}--{-# LANGUAGE TypeOperators #-}---- | This module defines type synonyms for SI units.--module Data.Dimensions.SI.Types where--import Data.Dimensions-import Data.Dimensions.SI--type Length = MkDim Meter-type Mass = MkDim Gram-type Time = MkDim Second-type Current = MkDim Ampere-type Temperature = MkDim Kelvin-type Quantity = MkDim Mole-type Luminosity = MkDim Candela--type Area = Length %^ Two-type Volume = Length %^ Three-type Velocity = Length %/ Time-type Acceleration = Length %/ (Time %^ Two)-type Wavenumber = Length %^ MOne-type Density = Mass %/ Volume-type SurfaceDensity = Mass %/ Area-type SpecificVolume = Volume %/ Mass-type CurrentDensity = Current %/ Area-type MagneticStrength = Current %/ Length-type Concentration = Quantity %/ Volume-type Luminance = Luminosity %/ Area--type Frequency = MkDim Hertz-type Force = MkDim Newton-type Pressure = MkDim Pascal-type Energy = MkDim Joule-type Power = MkDim Watt-type Charge = MkDim Coulomb-type ElectricPotential = MkDim Volt-type Capacitance = MkDim Farad-type Resistance = MkDim Ohm-type Conductance = MkDim Siemens-type MagneticFlux = MkDim Weber-type MagneticFluxDensity = MkDim Tesla-type Inductance = MkDim Henry-type LuminousFlux = MkDim Lumen-type Illuminance = MkDim Lux-type Kerma = MkDim Gray-type CatalyticActivity = MkDim Katal--type Momentum = Mass %* Velocity
− src/Data/Dimensions/Show.hs
@@ -1,71 +0,0 @@-{- Data/Dimensions/Show.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file defines Show instances for dimensioned quantities.--}--{-# LANGUAGE PolyKinds, DataKinds, TypeOperators, FlexibleInstances,- ScopedTypeVariables #-}---- | This module defines only a @Show@ instance for dimensioned quantities.--- The Show instance prints out the number stored internally with its canonical--- units.--module Data.Dimensions.Show () where--import Data.Typeable (Proxy(..))-import Data.List-import GHC.TypeLits (Sing, sing, SingI)--import Data.Dimensions.DimSpec-import Data.Dimensions.Dim-import Data.Dimensions.Z--class ShowDimSpec (dims :: [DimSpec *]) where- showDims :: Proxy dims -> ([String], [String])--instance ShowDimSpec '[] where- showDims _ = ([], [])--instance (ShowDimSpec rest, Show unit, SingI z)- => ShowDimSpec (D unit z ': rest) where- showDims _ =- let (nums, denoms) = showDims (Proxy :: Proxy rest)- baseStr = show (undefined :: unit)- power = szToInt (sing :: Sing z)- abs_power = abs power- str = if abs_power == 1- then baseStr- else baseStr ++ "^" ++ (show abs_power) in- case compare power 0 of- LT -> (nums, str : denoms)- EQ -> (nums, denoms)- GT -> (str : nums, denoms)--showDimSpec :: ShowDimSpec dimspec => Proxy dimspec -> String-showDimSpec p- = let (nums, denoms) = mapPair (build_string . sort) $ showDims p in- case (length nums, length denoms) of- (0, 0) -> ""- (_, 0) -> " " ++ nums- (0, _) -> " 1/" ++ denoms- (_, _) -> " " ++ nums ++ "/" ++ denoms- where- mapPair :: (a -> b) -> (a, a) -> (b, b)- mapPair f (x, y) = (f x, f y)-- build_string :: [String] -> String- build_string [] = ""- build_string [s] = s- build_string s = "(" ++ build_string_helper s ++ ")"-- build_string_helper :: [String] -> String- build_string_helper [] = ""- build_string_helper [s] = s- build_string_helper (h:t) = h ++ " * " ++ build_string_helper t--instance ShowDimSpec dims => Show (Dim dims) where- show (Dim d) = (show d ++ showDimSpec (Proxy :: Proxy dims))
− src/Data/Dimensions/TypePrelude.hs
@@ -1,45 +0,0 @@-{- Data/Dimensions/TypePrelude.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- Type-level prelude-like operations.- - Note to self: Consider using the type-prelude package instead.--}--{-# LANGUAGE TypeFamilies, DataKinds, PolyKinds, TypeOperators #-}--module Data.Dimensions.TypePrelude where---- | Extract the first element of a pair-type family Fst (x :: (a,b)) :: a-type instance Fst '(a,b) = a---- | Extract the second element of a pair-type family Snd (x :: (a,b)) :: b-type instance Snd '(a,b) = b---- | Type-level conditional-type family If (switch :: Bool) (true :: k) (false :: k) :: k where- If True t f = t- If False t f = f--infixr 3 :&&:--- | Type-level "and"-type family (a :: Bool) :&&: (b :: Bool) :: Bool where- False :&&: a = False- True :&&: a = a--infixr 2 :||:--- | Type-level "or"-type family (a :: Bool) :||: (b :: Bool) :: Bool where- False :||: a = a- True :||: a = True--infix 4 :=:--- | Type-level equality over @*@.-type family (a :: *) :=: (b :: *) :: Bool where- (a :: *) :=: (a :: *) = True- (a :: *) :=: (b :: *) = False
− src/Data/Dimensions/UnitCombinators.hs
@@ -1,72 +0,0 @@-{- Data/Dimensions/UnitCombinators.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file defines combinators to build more complex units from simpler ones.--}--{-# LANGUAGE TypeOperators, TypeFamilies, UndecidableInstances,- ScopedTypeVariables, DataKinds, FlexibleInstances #-}--module Data.Dimensions.UnitCombinators where--import GHC.TypeLits ( Sing, SingI, sing )--import Data.Dimensions.Units-import Data.Dimensions.DimSpec-import Data.Dimensions.Z--infixl 7 :*--- | Multiply two units to get another unit.--- For example: @type MetersSquared = Meter :* Meter@-data u1 :* u2 = u1 :* u2--instance (Unit u1, Unit u2) => Unit (u1 :* u2) where-- -- we override the default conversion lookup behavior- type BaseUnit (u1 :* u2) = Canonical- conversionRatio _ = undefined -- this should never be called-- type DimSpecsOf (u1 :* u2) = (DimSpecsOf u1) @+ (DimSpecsOf u2)- canonicalConvRatio _ = canonicalConvRatio (undefined :: u1) *- canonicalConvRatio (undefined :: u2)--infixl 7 :/--- | Divide two units to get another unit-data u1 :/ u2 = u1 :/ u2--instance (Unit u1, Unit u2) => Unit (u1 :/ u2) where- type BaseUnit (u1 :/ u2) = Canonical- conversionRatio _ = undefined -- this should never be called- type DimSpecsOf (u1 :/ u2) = (DimSpecsOf u1) @- (DimSpecsOf u2)- canonicalConvRatio _ = canonicalConvRatio (undefined :: u1) /- canonicalConvRatio (undefined :: u2)--infixr 8 :^--- | Raise a unit to a power, known at compile time-data unit :^ (power :: Z) = unit :^ Sing power--instance (Unit unit, SingI power) => Unit (unit :^ power) where- type BaseUnit (unit :^ power) = Canonical- conversionRatio _ = undefined-- type DimSpecsOf (unit :^ power) = (DimSpecsOf unit) @* power- canonicalConvRatio _ = canonicalConvRatio (undefined :: unit) ^^ (szToInt (sing :: Sing power))--infix 9 :@--- | Multiply a conversion ratio by some constant. Used for defining prefixes.-data prefix :@ unit = prefix :@ unit---- | A class for user-defined prefixes-class UnitPrefix prefix where- -- | This should return the desired multiplier for the prefix being defined.- -- This function must /not/ inspect its argument.- multiplier :: prefix -> Double--instance ( CheckCanonical unit ~ False- , Unit unit- , UnitPrefix prefix ) => Unit (prefix :@ unit) where- type BaseUnit (prefix :@ unit) = unit- conversionRatio _ = multiplier (undefined :: prefix)
− src/Data/Dimensions/Units.hs
@@ -1,108 +0,0 @@-{- Data/Dimensions/Units.hs-- The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file defines the class Unit, which is needed for- user-defined units.--}--{-# LANGUAGE TypeFamilies, DataKinds, DefaultSignatures, MultiParamTypeClasses,- ConstraintKinds, UndecidableInstances, FlexibleContexts,- FlexibleInstances, ScopedTypeVariables #-}--module Data.Dimensions.Units where--import Data.Dimensions.Z-import Data.Dimensions.DimSpec-import Data.Dimensions.Dim-import Data.Dimensions.TypePrelude---- | Dummy type use just to label canonical units. It does /not/ have a--- 'Unit' instance.-data Canonical---- | Class of units. Make an instance of this class to define a new unit.-class Unit unit where- -- | The base unit of this unit: what this unit is defined in terms of.- -- For units that are not defined in terms of anything else, the base unit- -- should be 'Canonical'.- type BaseUnit unit :: *-- -- | The conversion ratio /from/ the base unit /to/ this unit.- -- If left out, a conversion ratio of 1 is assumed.- --- -- For example:- --- -- > instance Unit Foot where- -- > type BaseUnit Foot = Meter- -- > conversionRatio _ = 0.3048- --- -- Implementations should /never/ examine their argument!- conversionRatio :: unit -> Double-- -- | The internal list of dimensions for a dimensioned quantity built from- -- this unit.- type DimSpecsOf unit :: [DimSpec *]- type DimSpecsOf unit = If (IsCanonical unit)- '[D unit One]- (DimSpecsOf (BaseUnit unit))-- -- if unspecified, assume a conversion ratio of 1- conversionRatio _ = 1-- -- | Compute the conversion from the underlying canonical unit to- -- this one. A default is provided that multiplies together the ratios- -- of all units between this one and the canonical one.- canonicalConvRatio :: unit -> Double- default canonicalConvRatio :: BaseHasConvRatio unit => unit -> Double- canonicalConvRatio u = conversionRatio u * baseUnitRatio u---- Abbreviation for creating a Dim (defined here to avoid a module cycle)--- | Make a dimensioned quantity capable of storing a value of a given unit.--- For example:------ > type Length = MkDim Meter-type MkDim unit = Dim (DimSpecsOf unit)---- | Is this unit a canonical unit?-type IsCanonical (unit :: *) = CheckCanonical (BaseUnit unit)---- | Is the argument the special datatype 'Canonical'?-type family CheckCanonical (base_unit :: *) :: Bool where- CheckCanonical Canonical = True- CheckCanonical unit = False--{- I want to say this. But type families are *eager* so I have to write- it another way.-type family CanonicalUnit (unit :: *) where- CanonicalUnit unit- = If (IsCanonical unit) unit (CanonicalUnit (BaseUnit unit))--}---- | Get the canonical unit from a given unit.--- For example: @CanonicalUnit Foot = Meter@-type CanonicalUnit (unit :: *) = CanonicalUnit' (BaseUnit unit) unit---- | Helper function in 'CanonicalUnit'-type family CanonicalUnit' (base_unit :: *) (unit :: *) :: * where- CanonicalUnit' Canonical unit = unit- CanonicalUnit' base unit = CanonicalUnit' (BaseUnit base) base---- | Essentially, a constraint that checks if a conversion ratio can be--- calculated for a @BaseUnit@ of a unit.-type BaseHasConvRatio unit = HasConvRatio (IsCanonical unit) unit---- | This is like 'Unit', but deals with 'Canonical'. It is necessary--- to be able to define 'canonicalConvRatio' in the right way.-class is_canonical ~ IsCanonical unit- => HasConvRatio (is_canonical :: Bool) (unit :: *) where- baseUnitRatio :: unit -> Double-instance True ~ IsCanonical canonical_unit- => HasConvRatio True canonical_unit where- baseUnitRatio _ = 1-instance ( False ~ IsCanonical noncanonical_unit- , Unit (BaseUnit noncanonical_unit) )- => HasConvRatio False noncanonical_unit where- baseUnitRatio _ = canonicalConvRatio (undefined :: BaseUnit noncanonical_unit)
− src/Data/Dimensions/Z.hs
@@ -1,165 +0,0 @@-{- Data/Dimensions/Z.hs- - The units Package- Copyright (c) 2013 Richard Eisenberg- eir@cis.upenn.edu-- This file contains a definition of integers at the type-level, in terms- of a promoted datatype 'Z'.--}--{-# LANGUAGE TypeFamilies, DataKinds, TypeOperators, UndecidableInstances,- GADTs, PolyKinds #-}---- | This module defines a datatype and operations to represent type-level--- integers. Though it's defined as part of the unitss package, it may be--- useful beyond dimensional analysis. If you have a compelling non-units--- use of this package, please let me (Richard, @eir@ at @cis.upenn.edu@)--- know.--module Data.Dimensions.Z where--import GHC.TypeLits ( Sing, SingI(..), SingE(..), KindIs(..) )---- | The datatype for type-level integers.-data Z = Zero | S Z | P Z---- | Convert a 'Z' to an 'Int'-zToInt :: Z -> Int-zToInt Zero = 0-zToInt (S z) = zToInt z + 1-zToInt (P z) = zToInt z - 1---- | Add one to an integer-type family Succ (z :: Z) :: Z where- Succ Zero = S Zero- Succ (P z) = z- Succ (S z) = S (S z)---- | Subtract one from an integer-type family Pred (z :: Z) :: Z where- Pred Zero = P Zero- Pred (P z) = P (P z)- Pred (S z) = z--infixl 6 #+--- | Add two integers-type family (a :: Z) #+ (b :: Z) :: Z where- Zero #+ z = z- (S z1) #+ (S z2) = S (S (z1 #+ z2))- (S z1) #+ Zero = S z1- (S z1) #+ (P z2) = z1 #+ z2- (P z1) #+ (S z2) = z1 #+ z2- (P z1) #+ Zero = P z1- (P z1) #+ (P z2) = P (P (z1 #+ z2))--infixl 6 #---- | Subtract two integers-type family (a :: Z) #- (b :: Z) :: Z where- z #- Zero = z- (S z1) #- (S z2) = z1 #- z2- Zero #- (S z2) = P (Zero #- z2)- (P z1) #- (S z2) = P (P (z1 #- z2))- (S z1) #- (P z2) = S (S (z1 #- z2))- Zero #- (P z2) = S (Zero #- z2)- (P z1) #- (P z2) = z1 #- z2--infixl 7 #*--- | Multiply two integers-type family (a :: Z) #* (b :: Z) :: Z where- Zero #* z = Zero- (S z1) #* z2 = (z1 #* z2) #+ z2- (P z1) #* z2 = (z1 #* z2) #- z2---- | Negate an integer-type family NegZ (z :: Z) :: Z where- NegZ Zero = Zero- NegZ (S z) = P (NegZ z)- NegZ (P z) = S (NegZ z)---- | Divide two integers-type family (a :: Z) #/ (b :: Z) :: Z where- Zero #/ b = Zero- a #/ (P b') = NegZ (a #/ (NegZ (P b')))- a #/ b = ZDiv b b a---- | Helper function for division-type family ZDiv (counter :: Z) (n :: Z) (z :: Z) :: Z where- ZDiv One n (S z') = S (z' #/ n)- ZDiv One n (P z') = P (z' #/ n)- ZDiv (S count') n (S z') = ZDiv count' n z'- ZDiv (S count') n (P z') = ZDiv count' n z'---- | Less-than comparison-type family (a :: Z) < (b :: Z) :: Bool where- Zero < Zero = False- Zero < (S n) = True- Zero < (P n) = False- (S n) < Zero = False- (S n) < (S n') = n < n'- (S n) < (P n') = False- (P n) < Zero = True- (P n) < (S n') = True- (P n) < (P n') = n < n'--type One = S Zero-type Two = S One-type Three = S Two-type Four = S Three-type Five = S Four--type MOne = P Zero-type MTwo = P MOne-type MThree = P MTwo-type MFour = P MThree-type MFive = P MFour------ Singleton for Z-data instance Sing (z :: Z) where- SZero :: Sing Zero- SS :: Sing z -> Sing (S z)- SP :: Sing z -> Sing (P z)--instance SingI Zero where- sing = SZero-instance SingI z => SingI (S z) where- sing = SS sing-instance SingI z => SingI (P z) where- sing = SP sing--instance SingE (KindParam :: KindIs Z) where- type DemoteRep (KindParam :: KindIs Z) = Z- fromSing SZero = Zero- fromSing (SS z) = S (fromSing z)- fromSing (SP z) = P (fromSing z)---- | This is the singleton value representing @Zero@ at the term level and--- at the type level, simultaneously. Used for raising units to powers.-pZero = SZero-pOne = SS pZero-pTwo = SS pOne-pThree = SS pTwo-pFour = SS pThree-pFive = SS pFour--pMOne = SP pZero-pMTwo = SP pMOne-pMThree = SP pMTwo-pMFour = SP pMThree-pMFive = SP pMFour---- | Add one to a singleton @Z@.-pSucc :: Sing z -> Sing (Succ z)-pSucc SZero = pOne-pSucc (SS z') = SS (SS z')-pSucc (SP z') = z'---- | Subtract one from a singleton @Z@.-pPred :: Sing z -> Sing (Pred z)-pPred SZero = pMOne-pPred (SS z') = z'-pPred (SP z') = SP (SP z')---- | Convert a singleton @Z@ to an @Int@.-szToInt :: Sing (z :: Z) -> Int-szToInt = zToInt . fromSing
units.cabal view
@@ -1,5 +1,5 @@ name: units-version: 1.0.1+version: 1.1 cabal-version: >= 1.10 synopsis: A domain-specific type system for dimensional analysis homepage: http://www.cis.upenn.edu/~eir/packages/units@@ -27,17 +27,17 @@ source-repository this type: git location: https://github.com/goldfirere/units.git- tag: v1.0.1+ tag: v1.1 library build-depends: - base >= 4.7 && < 5+ base >= 4.7 && < 5,+ singletons >= 0.9 exposed-modules: Data.Dimensions, Data.Dimensions.Show,- Data.Dimensions.Internal,+ Data.Dimensions.Poly, Data.Dimensions.Unsafe, Data.Dimensions.SI, Data.Dimensions.SI.Prefixes,- Data.Dimensions.SI.Types+ Data.Dimensions.SI.Types, Data.Dimensions.SI.Units other-modules: Data.Dimensions.Dim, Data.Dimensions.DimSpec, Data.Dimensions.Units, Data.Dimensions.UnitCombinators,- Data.Dimensions.TypePrelude, Data.Dimensions.Z- hs-source-dirs: src+ Data.Dimensions.Z default-language: Haskell2010