├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── Quantities.idr ├── Quantities ├── Core.idr ├── FreeAbelianGroup.idr ├── ImperialUnits.idr ├── Information.idr ├── NonSIUnits.idr ├── Power.idr ├── SIBaseQuantities.idr ├── SIBaseUnits.idr ├── SIDerivedQuantities.idr ├── SIDerivedUnits.idr ├── SIPrefixes.idr └── Screen.idr ├── README.md ├── examples ├── Documentation.idr └── Game.idr ├── images └── new-cuyama.jpg ├── quantities.ipkg ├── quantities.nix └── scripts ├── build-docs.sh └── publish-docs.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.ibc 2 | .DS_Store 3 | .cabal-sandbox 4 | cabal.sandbox.config -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: nix 2 | 3 | before_install: 4 | - nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs 5 | - nix-channel --update 6 | 7 | script: 8 | - nix-shell -p 'idrisPackages.with-packages [ ((import {}).idrisPackages.callPackage ./quantities.nix {}) ]' --run "idris --check examples/Documentation.idr examples/Game.idr" -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Since this library doesn't have version numbers (yet), the list below is a list of breaking changes. 2 | 3 | # 2015-11-08 4 | 5 | Capitalized all units. This change is necessary since Idris interprets the `watt` in `F watt` as an implicit type argument in version 0.9.20, since it begins with a lower-case letter. The alternative would have been to require the user to use qualified names: `F Quantities.SIDerivedUnits.watt` -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2013-2019 Tim Baumann, http://timbaumann.info 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the “Software”), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in 12 | all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Quantities.idr: -------------------------------------------------------------------------------- 1 | module Quantities 2 | 3 | import public Quantities.Core 4 | import public Quantities.SIBaseQuantities 5 | import public Quantities.SIDerivedQuantities 6 | import public Quantities.SIBaseUnits 7 | import public Quantities.SIDerivedUnits 8 | import public Quantities.SIPrefixes 9 | -------------------------------------------------------------------------------- /Quantities/Core.idr: -------------------------------------------------------------------------------- 1 | module Quantities.Core 2 | 3 | import public Quantities.FreeAbelianGroup 4 | import public Quantities.Power 5 | 6 | %default total 7 | %access public export 8 | 9 | ||| Elementary quantities 10 | record Dimension where 11 | constructor MkDimension 12 | name : String 13 | 14 | implementation Eq Dimension where 15 | (MkDimension a) == (MkDimension b) = a == b 16 | 17 | implementation Ord Dimension where 18 | compare (MkDimension a) (MkDimension b) = compare a b 19 | 20 | 21 | -- Compound quantities 22 | 23 | ||| A quantity is a property that can be measured. 24 | Quantity : Type 25 | Quantity = FreeAbGrp Dimension 26 | 27 | ||| The trivial quantity 28 | Scalar : Quantity 29 | Scalar = unit 30 | 31 | ||| Create a new quantity. 32 | mkQuantity : List (Dimension, Integer) -> Quantity 33 | mkQuantity = mkFreeAbGrp 34 | 35 | infixl 6 36 | 37 | -- Synonyms (quantites are multiplied, not added!) 38 | ||| Product quantity 39 | (<*>) : Ord a => FreeAbGrp a -> FreeAbGrp a -> FreeAbGrp a 40 | (<*>) = (<<+>>) 41 | 42 | ||| Quotient quantity 43 | () : Ord a => FreeAbGrp a -> FreeAbGrp a -> FreeAbGrp a 44 | a b = a <*> freeAbGrpInverse b 45 | 46 | ||| Convert dimensions to quantities 47 | implicit 48 | dimensionToQuantity : Dimension -> Quantity 49 | dimensionToQuantity = inject 50 | 51 | 52 | ||| Elementary Unit 53 | record ElemUnit (q : Quantity) where 54 | constructor MkElemUnit 55 | name : String 56 | conversionRate : Double 57 | 58 | -- ElemUnit with its quantity hidden 59 | data SomeElemUnit : Type where 60 | MkSomeElemUnit : (q : Quantity) -> ElemUnit q -> SomeElemUnit 61 | 62 | quantity : SomeElemUnit -> Quantity 63 | quantity (MkSomeElemUnit q _) = q 64 | 65 | elemUnit : (seu : SomeElemUnit) -> ElemUnit (quantity seu) 66 | elemUnit (MkSomeElemUnit _ u) = u 67 | 68 | name : SomeElemUnit -> String 69 | name x = name (elemUnit x) 70 | 71 | implementation Eq SomeElemUnit where 72 | a == b = quantity a == quantity b && name a == name b 73 | 74 | implementation Ord SomeElemUnit where 75 | compare a b with (compare (quantity a) (quantity b)) 76 | | LT = LT 77 | | GT = GT 78 | | EQ = compare (name a) (name b) 79 | 80 | implicit 81 | elemUnitToSomeElemUnitFreeAbGrp : ElemUnit q -> FreeAbGrp SomeElemUnit 82 | elemUnitToSomeElemUnitFreeAbGrp {q} u = inject (MkSomeElemUnit q u) 83 | 84 | conversionRate : SomeElemUnit -> Double 85 | conversionRate u = conversionRate (elemUnit u) 86 | 87 | joinedQuantity : FreeAbGrp SomeElemUnit -> Quantity 88 | joinedQuantity = lift quantity 89 | 90 | data Unit : Quantity -> Type where 91 | MkUnit : (exponent : Integer) -> (elemUnits : FreeAbGrp SomeElemUnit) -> 92 | Unit (joinedQuantity elemUnits) 93 | 94 | rewriteUnit : r = q -> Unit q -> Unit r 95 | rewriteUnit eq unit = rewrite eq in unit 96 | 97 | base10Exponent : Unit q -> Integer 98 | base10Exponent (MkUnit e _) = e 99 | 100 | someElemUnitFreeAbGrp : Unit q -> FreeAbGrp SomeElemUnit 101 | someElemUnitFreeAbGrp (MkUnit _ us) = us 102 | 103 | implementation Eq (Unit q) where 104 | x == y = base10Exponent x == base10Exponent y && 105 | someElemUnitFreeAbGrp x == someElemUnitFreeAbGrp y 106 | 107 | ||| The trivial unit 108 | One : Unit Scalar 109 | One = MkUnit 0 neutral 110 | 111 | ||| Multiples of ten 112 | Ten : Unit Scalar 113 | Ten = MkUnit 1 neutral 114 | 115 | ||| One hundredth 116 | Percent : Unit Scalar 117 | Percent = MkUnit (-2) neutral 118 | 119 | ||| One thousandth 120 | Promille : Unit Scalar 121 | Promille = MkUnit (-3) neutral 122 | 123 | ||| The trivial unit (synonymous with `one`) 124 | UnitLess : Unit Scalar 125 | UnitLess = One 126 | 127 | implicit 128 | elemUnitToUnit : {q : Quantity} -> ElemUnit q -> Unit q 129 | elemUnitToUnit {q} u = rewriteUnit eq (MkUnit 0 (inject (MkSomeElemUnit q u))) 130 | where eq = sym (inject_lift_lem quantity (MkSomeElemUnit q u)) 131 | 132 | ||| Compute conversion factor from the given unit to the base unit of the 133 | ||| corresponding quantity. 134 | joinedConversionRate : Unit q -> Double 135 | joinedConversionRate (MkUnit e (MkFreeAbGrp us)) = fromUnits * fromExponent 136 | where fromUnits = product $ map (\(u, i) => ((^) @{floatmultpower}) (conversionRate u) i) us 137 | fromExponent = ((^) @{floatmultpower}) 10 e 138 | 139 | ||| Constructs a new unit given a name and conversion factor from an existing unit. 140 | defineAsMultipleOf : String -> Double -> Unit q -> ElemUnit q 141 | defineAsMultipleOf name factor unit = MkElemUnit name (factor * joinedConversionRate unit) 142 | 143 | -- Syntax sugar for defining new units 144 | syntax "< one" [name] equals [factor] [unit] ">" = defineAsMultipleOf name factor unit 145 | 146 | implementation Show (Unit q) where 147 | show (MkUnit 0 (MkFreeAbGrp [])) = "unitLess" 148 | show (MkUnit e (MkFreeAbGrp [])) = "ten ^^ " ++ show e 149 | show (MkUnit e (MkFreeAbGrp (u :: us))) = if e == 0 then fromUnits 150 | else "ten ^^ " ++ show e ++ " <**> " ++ fromUnits 151 | where monom : (SomeElemUnit, Integer) -> String 152 | monom (unit, 1) = name unit 153 | monom (unit, i) = name unit ++ " ^^ " ++ show i 154 | fromUnits = monom u ++ concatMap ((" <**> " ++) . monom) us 155 | 156 | ||| Pretty-print a unit (using only ASCII characters) 157 | showUnit : Unit q -> String 158 | showUnit (MkUnit 0 (MkFreeAbGrp [])) = "" 159 | showUnit (MkUnit e (MkFreeAbGrp [])) = "10^" ++ show e 160 | showUnit (MkUnit e (MkFreeAbGrp (u :: us))) = if e == 0 then fromUnits 161 | else "10^" ++ show e ++ " " ++ fromUnits 162 | where monom : (SomeElemUnit, Integer) -> String 163 | monom (unit, 1) = name unit 164 | monom (unit, i) = name unit ++ "^" ++ show i 165 | fromUnits = monom u ++ concatMap ((" " ++) . monom) us 166 | 167 | toSuperScript : Char -> Char 168 | toSuperScript '1' = '¹' 169 | toSuperScript '2' = '²' 170 | toSuperScript '3' = '³' 171 | toSuperScript '4' = '⁴' 172 | toSuperScript '5' = '⁵' 173 | toSuperScript '6' = '⁶' 174 | toSuperScript '7' = '⁷' 175 | toSuperScript '8' = '⁸' 176 | toSuperScript '9' = '⁹' 177 | toSuperScript '0' = '⁰' 178 | toSuperScript '-' = '⁻' 179 | toSuperScript x = x 180 | 181 | toSuper : String -> String 182 | toSuper = pack . map toSuperScript . unpack 183 | 184 | ||| Pretty-print a unit 185 | showUnitUnicode : Unit q -> String 186 | showUnitUnicode (MkUnit 0 (MkFreeAbGrp [])) = "" 187 | showUnitUnicode (MkUnit e (MkFreeAbGrp [])) = "10" ++ toSuper (show e) 188 | showUnitUnicode (MkUnit e (MkFreeAbGrp (u :: us))) = if e == 0 then fromUnits 189 | else "10" ++ toSuper (show e) ++ " " ++ fromUnits 190 | where monom : (SomeElemUnit, Integer) -> String 191 | monom (unit, 1) = name unit 192 | monom (unit, i) = name unit ++ toSuper (show i) 193 | fromUnits = monom u ++ concatMap ((" " ++) . monom) us 194 | 195 | infixr 10 ^^ 196 | ||| Power unit 197 | (^^) : Unit q -> (i : Integer) -> Unit (q ^ i) 198 | (^^) (MkUnit e us) i = rewriteUnit eq (MkUnit (i*e) (us ^ i)) 199 | where eq = sym (lift_power_lem quantity us i) 200 | 201 | ||| Inverse unit (e.g. the inverse of `second` is `one second` a.k.a. `hertz`) 202 | unitInverse : {q : Quantity} -> Unit q -> Unit (freeAbGrpInverse q) 203 | unitInverse {q} u = rewrite (freeabgrppower_correct q (-1)) 204 | in u ^^ (-1) 205 | 206 | infixl 6 <**>, 207 | 208 | ||| Product unit 209 | (<**>) : Unit r -> Unit s -> Unit (r <*> s) 210 | (<**>) (MkUnit e rs) (MkUnit f ss) = rewriteUnit eq (MkUnit (e+f) (rs <*> ss)) 211 | where eq = sym (lift_mult_lem quantity rs ss) 212 | 213 | ||| Quotient unit 214 | () : Unit r -> Unit s -> Unit (r s) 215 | () a b = a <**> unitInverse b 216 | 217 | infixl 5 =| -- sensible? 218 | ||| Numbers tagged with a unit 219 | data Measurement : {q : Quantity} -> Unit q -> Type -> Type where 220 | (=|) : a -> (u : Unit q) -> Measurement u a 221 | 222 | ||| Extract the number 223 | getValue : {q : Quantity} -> {u : Unit q} -> 224 | Measurement {q} u a -> a 225 | getValue (x =| _) = x 226 | 227 | implementation Functor (Measurement {q} u) where 228 | map f (x =| _) = f x =| u 229 | 230 | implementation Eq a => Eq (Measurement {q} u a) where 231 | (x =| _) == (y =| _) = x == y 232 | 233 | implementation Ord a => Ord (Measurement {q} u a) where 234 | compare (x =| _) (y =| _) = compare x y 235 | 236 | implementation Show a => Show (Measurement {q} u a) where 237 | show (x =| _) = show x ++ " =| " ++ show u 238 | 239 | implementation Num a => Semigroup (Measurement {q} u a) where 240 | (x =| _) <+> (y =| _) = (x + y) =| u 241 | 242 | implementation Num a => Monoid (Measurement {q} u a) where 243 | neutral = fromInteger 0 =| u 244 | 245 | implementation (Neg a, Num a) => Group (Measurement {q} u a) where 246 | inverse (x =| _) = (-x) =| u 247 | 248 | implementation (Neg a, Num a) => AbelianGroup (Measurement {q} u a) where 249 | 250 | ||| Pretty-print a measurement (using only ASCII characters) 251 | showMeasurement : Show a => {q : Quantity} -> {u : Unit q} -> 252 | (Measurement u a) -> String 253 | showMeasurement (x =| u) = 254 | show x ++ (if base10Exponent u == 0 then " " else "*") ++ showUnit u 255 | 256 | ||| Pretty-print a measurement (using only ASCII characters) 257 | showMeasurementUnicode : Show a => {q : Quantity} -> {u : Unit q} -> 258 | (Measurement u a) -> String 259 | showMeasurementUnicode (x =| u) = 260 | show x ++ (if base10Exponent u == 0 then " " else "·") ++ showUnit u 261 | 262 | infixl 5 :| 263 | 264 | ||| Type synonym for `Measurement` 265 | (:|) : Unit q -> Type -> Type 266 | (:|) = Measurement 267 | 268 | ||| Flatten nested measurements 269 | joinUnits : {q : Quantity} -> {r : Quantity} -> {u : Unit q} -> {v : Unit r} -> 270 | (u :| (v :| a)) -> (u <**> v) :| a 271 | joinUnits ((x =| v) =| u) = x =| (u <**> v) 272 | 273 | 274 | ||| Double with a unit 275 | F : Unit q -> Type 276 | F u = Measurement u Double 277 | 278 | 279 | infixl 9 |*|,|/| 280 | 281 | ||| Product measurement 282 | (|*|) : Num a => {q : Quantity} -> {r : Quantity} -> {u : Unit q} -> {v : Unit r} -> 283 | u :| a -> v :| a -> (u <**> v) :| a 284 | (|*|) (x =| u) (y =| v) = (x*y) =| (u <**> v) 285 | 286 | ||| Quotient measurement (the second measurement mustn't be zero!) 287 | (|/|) : {q : Quantity} -> {r : Quantity} -> {u : Unit q} -> {v : Unit r} -> 288 | F u -> F v -> F (u v) 289 | (|/|) (x =| u) (y =| v) = (x/y) =| (u v) 290 | 291 | infixl 10 |^| 292 | 293 | ||| Power measurement 294 | (|^|) : {q : Quantity} -> {u : Unit q} -> F u -> (i : Integer) -> F (u ^^ i) 295 | (|^|) (x =| u) i = (((^) @{floatmultpower}) x i) =| u ^^ i 296 | 297 | ||| Square root measurement 298 | sqrt : {q : Quantity} -> {u : Unit q} -> F (u ^^ 2) -> F u 299 | sqrt {q} {u} (x =| _) = (sqrt x) =| u 300 | 301 | ||| Round measurement to the next integer below 302 | floor : {q : Quantity} -> {u : Unit q} -> F u -> F u 303 | floor = map floor 304 | 305 | ||| Round measurement to the next integer above 306 | ceiling : {q : Quantity} -> {u : Unit q} -> F u -> F u 307 | ceiling = map ceiling 308 | 309 | ||| Convert measurements to a given unit 310 | convertTo : {from : Unit q} -> (to : Unit q) -> F from -> F to 311 | convertTo to (x =| from) = (x * (rateFrom / rateTo)) =| to 312 | where rateFrom = joinedConversionRate from 313 | rateTo = joinedConversionRate to 314 | 315 | ||| Flipped version of `convertTo` 316 | as : {from : Unit q} -> F from -> (to : Unit q) -> F to 317 | as x u = convertTo u x 318 | 319 | ||| Convert with implicit target unit 320 | convert : {from : Unit q} -> {to : Unit q} -> F from -> F to 321 | convert {to=to} x = convertTo to x 322 | 323 | ||| Promote values to measurements of the trivial quantity 324 | implicit 325 | toUnitLess : a -> Measurement unitLess a 326 | toUnitLess x = x =| unitLess 327 | 328 | implementation Num a => Num (Measurement unitLess a) where 329 | x + y = (getValue x + getValue y) =| unitLess 330 | x * y = (getValue x * getValue y) =| unitLess 331 | fromInteger i = fromInteger i =| unitLess 332 | 333 | implementation Neg a => Neg (Measurement unitLess a) where 334 | negate x = negate (getValue x) =| unitLess 335 | x - y = (getValue x - getValue y) =| unitLess 336 | 337 | implementation Abs a => Abs (Measurement unitLess a) where 338 | abs x = abs (getValue x) =| unitLess 339 | -------------------------------------------------------------------------------- /Quantities/FreeAbelianGroup.idr: -------------------------------------------------------------------------------- 1 | module Quantities.FreeAbelianGroup 2 | 3 | import Quantities.Power 4 | 5 | %default total 6 | %access public export 7 | 8 | mergeWithBy : (k -> k -> Ordering) -> (v -> v -> v) -> 9 | List (k, v) -> List (k, v) -> List (k, v) 10 | mergeWithBy _ _ [] ys = ys 11 | mergeWithBy _ _ xs [] = xs 12 | mergeWithBy order combine ((k1, v1) :: xs) ((k2, v2) :: ys) = let o = order k1 k2 in 13 | if o == LT then (k1, v1) :: mergeWithBy order combine xs ((k2, v2) :: ys) 14 | else if o == GT then (k2, v2) :: mergeWithBy order combine ((k1, v1) :: xs) ys 15 | else (k1, combine v1 v2) :: mergeWithBy order combine xs ys 16 | 17 | mergeWith : Ord k => (v -> v -> v) -> 18 | List (k, v) -> List (k, v) -> List (k, v) 19 | mergeWith = mergeWithBy compare 20 | 21 | filterValues : (v -> Bool) -> List (k, v) -> List (k, v) 22 | filterValues p = filter (p . snd) 23 | 24 | mapValue : (v -> w) -> List (k, v) -> List (k, w) 25 | mapValue f = map (\(k, v) => (k, f v)) 26 | 27 | data FreeAbGrp : Type -> Type where 28 | MkFreeAbGrp : {a : Type} -> (List (a, Integer)) -> FreeAbGrp a 29 | 30 | mkFreeAbGrp : Ord a => List (a, Integer) -> FreeAbGrp a 31 | mkFreeAbGrp = MkFreeAbGrp . filterValues (\x => x /= 0) 32 | . foldr (\x => mergeWith (+) [x]) [] 33 | 34 | unit : FreeAbGrp a 35 | unit = MkFreeAbGrp [] 36 | 37 | implicit 38 | inject : a -> FreeAbGrp a 39 | inject x = MkFreeAbGrp [(x, 1)] 40 | 41 | freeAbGrpPower : FreeAbGrp a -> Integer -> FreeAbGrp a 42 | freeAbGrpPower _ 0 = unit 43 | freeAbGrpPower (MkFreeAbGrp xs) i = MkFreeAbGrp $ mapValue (i*) xs 44 | 45 | freeAbGrpInverse : FreeAbGrp a -> FreeAbGrp a 46 | freeAbGrpInverse x = freeAbGrpPower x (-1) 47 | 48 | infixl 6 <<+>> 49 | (<<+>>) : Ord a => FreeAbGrp a -> FreeAbGrp a -> FreeAbGrp a 50 | (MkFreeAbGrp xs) <<+>> (MkFreeAbGrp ys) = MkFreeAbGrp $ filterValues (\x => x /= 0) $ mergeWithBy compare (+) xs ys 51 | 52 | implementation Eq a => Eq (FreeAbGrp a) where 53 | (MkFreeAbGrp xs) == (MkFreeAbGrp ys) = xs == ys 54 | 55 | implementation Ord a => Ord (FreeAbGrp a) where 56 | compare (MkFreeAbGrp xs) (MkFreeAbGrp ys) = compare xs ys 57 | 58 | implementation [freeabgrppower] Power (FreeAbGrp a) where 59 | (^) = freeAbGrpPower 60 | 61 | implementation Ord a => Semigroup (FreeAbGrp a) where 62 | (<+>) = (<<+>>) 63 | 64 | implementation Ord a => Monoid (FreeAbGrp a) where 65 | neutral = unit 66 | 67 | implementation Ord a => Group (FreeAbGrp a) where 68 | inverse = freeAbGrpInverse 69 | 70 | implementation Ord a => AbelianGroup (FreeAbGrp a) where 71 | 72 | -- Lift a function A -> G to a group homomorphism between the freely generated 73 | -- abelian group of A to the group G. 74 | lift : (Group g, Power g) => (a -> g) -> FreeAbGrp a -> g 75 | lift f (MkFreeAbGrp xs) = concatMap (\(x, i) => ((f x) ^ i)) xs 76 | 77 | inject_lift_lem : (Group g, Power g) => (f : a -> g) -> (x : a) -> lift f (inject x) = f x 78 | inject_lift_lem f x = really_believe_me (Refl {x=(lift f (inject x))}) 79 | 80 | lift_power_lem : (Group g, Power g, Ord a) => (f : a -> g) -> (x : FreeAbGrp a) -> 81 | (i : Integer) -> lift f (x ^ i) = lift f x ^ i 82 | lift_power_lem f x i = really_believe_me (Refl {x=(lift f (x ^ i))}) 83 | 84 | lift_mult_lem : (Ord a, Group g, Power g) => (f : a -> g) -> (x : FreeAbGrp a) -> 85 | (y : FreeAbGrp a) -> lift f (x <+> y) = lift f x <+> lift f y 86 | lift_mult_lem f x y = really_believe_me (Refl {x=(lift f (x <+> y))}) 87 | 88 | freeabgrppower_correct : (Ord a) => (x : FreeAbGrp a) -> (i : Integer) -> freeAbGrpPower x i = (^) x i 89 | freeabgrppower_correct x i = really_believe_me (Refl {x=(freeAbGrpPower x i)}) 90 | -------------------------------------------------------------------------------- /Quantities/ImperialUnits.idr: -------------------------------------------------------------------------------- 1 | module Quantities.ImperialUnits 2 | 3 | import Quantities.Core 4 | import Quantities.SIBaseQuantities 5 | import Quantities.SIPrefixes 6 | import Quantities.SIBaseUnits 7 | import Quantities.SIDerivedQuantities 8 | import Quantities.NonSIUnits 9 | 10 | %default total 11 | %access public export 12 | 13 | 14 | -- Based on http://en.wikipedia.org/wiki/Imperial_units 15 | 16 | 17 | -- Length 18 | 19 | Thou : ElemUnit Length 20 | Thou = < one "th" equals 25.4 (micro Metre) > 21 | Th : ElemUnit Length 22 | Th = Thou 23 | 24 | Inch : ElemUnit Length 25 | Inch = < one "in" equals 2.54 Centimetre > 26 | In_ : ElemUnit Length 27 | In_ = Inch 28 | 29 | Foot : ElemUnit Length 30 | Foot = < one "ft" equals 12 Inch > 31 | Ft : ElemUnit Length 32 | Ft = Foot 33 | 34 | Yard : ElemUnit Length 35 | Yard = < one "yd" equals 3 Foot > 36 | Yd : ElemUnit Length 37 | Yd = Yard 38 | 39 | Chain : ElemUnit Length 40 | Chain = < one "ch" equals 22 Yard > 41 | Ch : ElemUnit Length 42 | Ch = Chain 43 | 44 | Furlong : ElemUnit Length 45 | Furlong = < one "fur" equals 10 Chain > 46 | Fur : ElemUnit Length 47 | Fur = Furlong 48 | 49 | Mile : ElemUnit Length 50 | Mile = < one "mi" equals 1760 Yard > 51 | Mi : ElemUnit Length 52 | Mi = Mile 53 | 54 | League : ElemUnit Length 55 | League = < one "lea" equals 3 Mile > 56 | Lea : ElemUnit Length 57 | Lea = League 58 | 59 | -- Maritime units 60 | 61 | Fathom : ElemUnit Length 62 | Fathom = < one "ftm" equals 6.08 Foot > 63 | Ftm : ElemUnit Length 64 | Ftm = Fathom 65 | 66 | Cable : ElemUnit Length 67 | Cable = < one "cable" equals 608 Foot > 68 | 69 | NauticalMile : ElemUnit Length 70 | NauticalMile = < one "nmi" equals 1852 Metre > 71 | Nmi : ElemUnit Length 72 | Nmi = NauticalMile 73 | 74 | -- Gunter's survey units 75 | 76 | Link : ElemUnit Length 77 | Link = < one "link" equals (1/100) Chain > 78 | 79 | Rod : ElemUnit Length 80 | Rod = < one "rod" equals (1/4) Chain > 81 | 82 | 83 | -- Speed 84 | 85 | Knot : ElemUnit Speed 86 | Knot = < one "kn" equals 1 (NauticalMile Hour) > 87 | Kn : ElemUnit Speed 88 | Kn = Knot 89 | 90 | 91 | -- Area 92 | 93 | Perch : ElemUnit Area 94 | Perch = < one "perch" equals 1 (Rod ^^ 2) > 95 | 96 | Rood : ElemUnit Area 97 | Rood = < one "rood" equals 1 (Furlong <**> Rod) > 98 | 99 | Acre : ElemUnit Area 100 | Acre = < one "acre" equals 1 (Furlong <**> Chain) > 101 | 102 | 103 | -- Volume 104 | 105 | FluidOunce : ElemUnit Volume 106 | FluidOunce = < one "floz" equals 28.4130625 (milli $ (deci Metre) ^^ 3) > 107 | Floz : ElemUnit Volume 108 | Floz = FluidOunce 109 | 110 | Gill : ElemUnit Volume 111 | Gill = < one "gi" equals 5 FluidOunce > 112 | Gi : ElemUnit Volume 113 | Gi = Gill 114 | 115 | Pint : ElemUnit Volume 116 | Pint = < one "pt" equals 20 FluidOunce > 117 | Pt : ElemUnit Volume 118 | Pt = Pint 119 | 120 | Quart : ElemUnit Volume 121 | Quart = < one "qt" equals 40 FluidOunce > 122 | Qt : ElemUnit Volume 123 | Qt = Quart 124 | 125 | Gallon : ElemUnit Volume 126 | Gallon = < one "gal" equals 160 FluidOunce > 127 | Gal : ElemUnit Volume 128 | Gal = Gallon 129 | 130 | -- British apothecaries' volume measures 131 | 132 | Minim : ElemUnit Volume 133 | Minim = < one "min" equals 59.1938802083 (micro $ (deci Metre) ^^ 3) > 134 | Min : ElemUnit Volume 135 | Min = Minim 136 | 137 | FluidScruple : ElemUnit Volume 138 | FluidScruple = < one "fls" equals 20 Minim > 139 | Fls : ElemUnit Volume 140 | Fls = FluidScruple 141 | 142 | FluidDrachm : ElemUnit Volume 143 | FluidDrachm = < one "fldr" equals 3 FluidScruple > 144 | Fldr : ElemUnit Volume 145 | Fldr = FluidDrachm 146 | 147 | 148 | -- Mass 149 | 150 | Pound : ElemUnit Mass 151 | Pound = < one "lb" equals 453.59237 Gram > 152 | Lb : ElemUnit Mass 153 | Lb = Pound 154 | 155 | Grain : ElemUnit Mass 156 | Grain = < one "gr" equals (1/7000) Pound > 157 | Gr : ElemUnit Mass 158 | Gr = Grain 159 | 160 | Drachm : ElemUnit Mass 161 | Drachm = < one "dr" equals (1/256) Pound > 162 | Dr : ElemUnit Mass 163 | Dr = Drachm 164 | 165 | Ounce : ElemUnit Mass 166 | Ounce = < one "oz" equals (1/16) Pound > 167 | Oz : ElemUnit Mass 168 | Oz = Ounce 169 | 170 | Stone : ElemUnit Mass 171 | Stone = < one "st" equals 14 Pound > 172 | St : ElemUnit Mass 173 | St = Stone 174 | 175 | Quarter : ElemUnit Mass 176 | Quarter = < one "qtr" equals 28 Pound > 177 | Qtr : ElemUnit Mass 178 | Qtr = Quarter 179 | 180 | Hundredweight : ElemUnit Mass 181 | Hundredweight = < one "cwt" equals 112 Pound > 182 | Cwt : ElemUnit Mass 183 | Cwt = Hundredweight 184 | 185 | Ton : ElemUnit Mass 186 | Ton = < one "ton" equals 2240 Pound > 187 | 188 | 189 | -- Energy 190 | 191 | FootPound : ElemUnit Energy 192 | FootPound = < one "ftlb" equals 1 (Foot <**> Pound <**> G_0) > 193 | Ftlb : ElemUnit Energy 194 | Ftlb = FootPound 195 | 196 | 197 | -- Power 198 | 199 | MechanicalHorsepower : ElemUnit Power 200 | MechanicalHorsepower = < one "hp" equals 550 (FootPound Second) > 201 | ImperialHorsepower : ElemUnit Power 202 | ImperialHorsepower = MechanicalHorsepower 203 | Horsepower : ElemUnit Power 204 | Horsepower = MechanicalHorsepower 205 | Hp : ElemUnit Power 206 | Hp = MechanicalHorsepower 207 | -------------------------------------------------------------------------------- /Quantities/Information.idr: -------------------------------------------------------------------------------- 1 | module Quantities.Information 2 | 3 | import Quantities.Core 4 | 5 | %default total 6 | %access public export 7 | 8 | Information : Dimension 9 | Information = MkDimension "Information" 10 | 11 | Bit : ElemUnit Information 12 | Bit = MkElemUnit "bit" 1 13 | 14 | Byte : ElemUnit Information 15 | Byte = < one "byte" equals 8 Bit > 16 | 17 | -- Binary prefixes for multiples of bits/bytes 18 | -- Based on http://en.wikipedia.org/wiki/Binary_prefix 19 | 20 | twoToTheTen : String -> Nat -> ElemUnit q -> ElemUnit q 21 | twoToTheTen pre power (MkElemUnit name f) = 22 | < one (pre ++ name) equals (pow 1024.0 power) (MkElemUnit name f) > 23 | 24 | kibi : ElemUnit q -> ElemUnit q 25 | kibi = twoToTheTen "kibi" 1 26 | ki : ElemUnit q -> ElemUnit q 27 | ki = kibi 28 | 29 | mebi : ElemUnit q -> ElemUnit q 30 | mebi = twoToTheTen "mebi" 2 31 | mi : ElemUnit q -> ElemUnit q 32 | mi = mebi 33 | 34 | gibi : ElemUnit q -> ElemUnit q 35 | gibi = twoToTheTen "gibi" 3 36 | gi : ElemUnit q -> ElemUnit q 37 | gi = gibi 38 | 39 | tebi : ElemUnit q -> ElemUnit q 40 | tebi = twoToTheTen "tebi" 4 41 | ti : ElemUnit q -> ElemUnit q 42 | ti = tebi 43 | 44 | pebi : ElemUnit q -> ElemUnit q 45 | pebi = twoToTheTen "pebi" 5 46 | pi : ElemUnit q -> ElemUnit q 47 | pi = pebi 48 | 49 | exbi : ElemUnit q -> ElemUnit q 50 | exbi = twoToTheTen "exbi" 6 51 | ei : ElemUnit q -> ElemUnit q 52 | ei = exbi 53 | 54 | zebi : ElemUnit q -> ElemUnit q 55 | zebi = twoToTheTen "zebi" 7 56 | zi : ElemUnit q -> ElemUnit q 57 | zi = zebi 58 | 59 | yobi : ElemUnit q -> ElemUnit q 60 | yobi = twoToTheTen "yobi" 8 61 | yi : ElemUnit q -> ElemUnit q 62 | yi = yobi 63 | 64 | -- Please Note: kibi byte /= kilo byte 65 | -------------------------------------------------------------------------------- /Quantities/NonSIUnits.idr: -------------------------------------------------------------------------------- 1 | module Quantities.NonSIUnits 2 | 3 | import Quantities.FreeAbelianGroup 4 | import Quantities.Core 5 | import Quantities.SIBaseQuantities 6 | import Quantities.SIDerivedQuantities 7 | import Quantities.SIPrefixes 8 | import Quantities.SIBaseUnits 9 | import Quantities.SIDerivedUnits 10 | 11 | %default total 12 | %access public export 13 | 14 | 15 | -- Based on http://en.wikipedia.org/wiki/Non-SI_units_mentioned_in_the_SI 16 | 17 | Minute : ElemUnit Time 18 | Minute = < one "min" equals 60 Second > 19 | Min : ElemUnit Time 20 | Min = Minute 21 | 22 | Hour : ElemUnit Time 23 | Hour = < one "h" equals 60 Minute > 24 | H : ElemUnit Time 25 | H = Hour 26 | 27 | Day : ElemUnit Time 28 | Day = < one "d" equals 24 Hour > 29 | D : ElemUnit Time 30 | D = Day 31 | 32 | Week : ElemUnit Time 33 | Week = < one "week" equals 7 Day > 34 | 35 | -- Julian year 36 | Year : ElemUnit Time 37 | Year = < one "a" equals 365.25 Day > 38 | JulianYear : ElemUnit Time 39 | JulianYear = Year 40 | A : ElemUnit Time 41 | A = Year 42 | 43 | Century : Unit Time 44 | Century = hecto Year 45 | 46 | Millenium : Unit Time 47 | Millenium = kilo Year 48 | 49 | Tonne : ElemUnit Mass 50 | Tonne = < one "t" equals 1000 Kg > 51 | T : ElemUnit Mass 52 | T = Tonne 53 | 54 | Degree : ElemUnit PlaneAngle 55 | Degree = < one "deg" equals (pi / 180) Rad > 56 | Deg : ElemUnit PlaneAngle 57 | Deg = Degree 58 | 59 | Arcmin : ElemUnit PlaneAngle 60 | Arcmin = < one "arcmin" equals (1/60) Degree > 61 | 62 | Arcsec : ElemUnit PlaneAngle 63 | Arcsec = < one "arcsec" equals (1/60) Arcmin > 64 | 65 | -- Ångström (Å) 66 | Angstrom : ElemUnit Length 67 | Angstrom = < one "angstrom" equals 0.1 (nano Metre) > 68 | 69 | AstronomicalUnit : ElemUnit Length 70 | AstronomicalUnit = < one "au" equals 149597870700 Metre > 71 | Au : ElemUnit Length 72 | Au = AstronomicalUnit 73 | 74 | StandardGravity : ElemUnit Acceleration 75 | --StandardGravity = < one "g_0" equals 9.80665 (Metre (Second ^^ 2)) > 76 | StandardGravity = defineAsMultipleOf "g_0" 9.80665 (Metre (Second ^^ 2)) 77 | G_0 : ElemUnit Acceleration 78 | G_0 = StandardGravity 79 | 80 | RotationsPerMinute : Unit Frequency 81 | RotationsPerMinute = One Minute 82 | Rpm : Unit Frequency 83 | Rpm = RotationsPerMinute 84 | 85 | -- Use this only for relative temparature! Not suitable for conversions of 86 | -- absolute temperature! 87 | 88 | Fahrenheit : ElemUnit Temperature 89 | Fahrenheit = < one "dF" equals (5/9) K > -- °F 90 | DF : ElemUnit Temperature 91 | DF = Fahrenheit 92 | 93 | Are : ElemUnit Area 94 | Are = < one "are" equals 100 (Metre ^^ 2) > 95 | 96 | Hectare : ElemUnit Area 97 | Hectare = < one "ha" equals 1 ((hecto Metre) ^^ 2) > 98 | Ha : ElemUnit Area 99 | Ha = Hectare 100 | 101 | Barn : ElemUnit Area 102 | Barn = < one "b" equals 100 ((femto Metre) ^^ 2) > 103 | B : ElemUnit Area 104 | B = Barn 105 | 106 | Litre : ElemUnit Volume 107 | Litre = < one "l" equals 1 (milli (Metre ^^ 3)) > 108 | Liter : ElemUnit Volume 109 | Liter = Litre 110 | L : ElemUnit Volume 111 | L = Litre 112 | 113 | Bar : ElemUnit Pressure 114 | Bar = < one "bar" equals 100 (kilo Pascal) > 115 | 116 | MillimetreOfMercury : ElemUnit Pressure 117 | MillimetreOfMercury = < one "mmHg" equals 133.322 Pascal > 118 | MmHg : ElemUnit Pressure 119 | MmHg = MillimetreOfMercury 120 | 121 | Calorie : ElemUnit Energy 122 | Calorie = < one "cal" equals 4.18400 Joule > 123 | ThermochemicalCalorie : ElemUnit Energy 124 | ThermochemicalCalorie = Calorie 125 | Cal : ElemUnit Energy 126 | Cal = Calorie 127 | 128 | 129 | -- Non-SI units whose values in SI must be determined experimentally 130 | 131 | Electronvolt : ElemUnit Energy 132 | Electronvolt = < one "eV" equals 1.60217653 (Ten ^^ -19 <**> Joule) > 133 | EV : ElemUnit Energy 134 | EV = Electronvolt 135 | 136 | Dalton : ElemUnit Mass 137 | Dalton = < one "Da" equals 1.66053886 (Ten ^^ -27 <**> Kilogram) > 138 | Da : ElemUnit Mass 139 | Da = Dalton 140 | UnifiedAtomicMassUnit : ElemUnit Mass 141 | UnifiedAtomicMassUnit = Dalton 142 | U : ElemUnit Mass 143 | U = Dalton 144 | 145 | -- Atomic and natural units 146 | 147 | ElementaryCharge : ElemUnit ElectricCharge 148 | ElementaryCharge = < one "e" equals 1.60217653 (Ten ^^ -19 <**> Coulomb) > 149 | E : ElemUnit ElectricCharge 150 | E = ElementaryCharge 151 | 152 | MassOfElectron : ElemUnit Mass 153 | MassOfElectron = < one "m_e" equals 9.1093826 (Ten ^^ -31 <**> Kilogram) > 154 | ElectronMass : ElemUnit Mass 155 | ElectronMass = MassOfElectron 156 | M_e : ElemUnit Mass 157 | M_e = MassOfElectron 158 | 159 | BohrRadius : ElemUnit Length 160 | BohrRadius = < one "a_0" equals 0.5291772108 (Ten ^^ -10 <**> Metre) > 161 | Bohr : ElemUnit Length 162 | Bohr = BohrRadius 163 | A_0 : ElemUnit Length 164 | A_0 = BohrRadius 165 | 166 | HartreeEnergy : ElemUnit Energy 167 | HartreeEnergy = < one "E_h" equals 4.35974417 (Ten ^^ -18 <**> Joule) > 168 | Hartree : ElemUnit Energy 169 | Hartree = HartreeEnergy 170 | E_h : ElemUnit Energy 171 | E_h = HartreeEnergy 172 | 173 | PlanckConstant : ElemUnit (Energy <*> Time) 174 | PlanckConstant = < one "h" equals 6.62606957 (Joule <**> Second) > 175 | H_ : ElemUnit (Energy <*> Time) 176 | H_ = PlanckConstant 177 | 178 | ReducedPlanckConstant : ElemUnit (Energy <*> Time) 179 | ReducedPlanckConstant = < one "hBar" equals (1 / (2*pi)) (Joule <**> Second) > 180 | HBar : ElemUnit (Energy <*> Time) 181 | HBar = ReducedPlanckConstant 182 | 183 | AtomicUnitOfTime : ElemUnit Time 184 | AtomicUnitOfTime = < one "auOfTime" equals 1 (HBar Hartree) > 185 | AuOfTime : ElemUnit Time 186 | AuOfTime = AtomicUnitOfTime 187 | 188 | SpeedOfLight : ElemUnit Speed 189 | SpeedOfLight = < one "c_0" equals 299792458 (Metre Second) > 190 | C_0 : ElemUnit Speed 191 | C_0 = SpeedOfLight 192 | 193 | NaturalUnitOfTime : ElemUnit Time 194 | NaturalUnitOfTime = < one "nuOfTime" equals 1 (HBar (M_e <**> (C_0 ^^ 2))) > 195 | NuOfTime : ElemUnit Time 196 | NuOfTime = NaturalUnitOfTime 197 | 198 | LightSecond : ElemUnit Length 199 | LightSecond = < one "ls" equals 1 (Second <**> SpeedOfLight) > 200 | Ls : ElemUnit Length 201 | Ls = LightSecond 202 | 203 | LightMinute : ElemUnit Length 204 | LightMinute = < one "lmin" equals 1 (Minute <**> SpeedOfLight) > 205 | Lmin : ElemUnit Length 206 | Lmin = LightMinute 207 | 208 | LightHour : ElemUnit Length 209 | LightHour = < one "lh" equals 1 (Hour <**> SpeedOfLight) > 210 | Lh : ElemUnit Length 211 | Lh = LightHour 212 | 213 | LightDay : ElemUnit Length 214 | LightDay = < one "ld" equals 1 (Day <**> SpeedOfLight) > 215 | Ld : ElemUnit Length 216 | Ld = LightDay 217 | 218 | LightWeek : ElemUnit Length 219 | LightWeek = < one "ld" equals 1 (Week <**> SpeedOfLight) > 220 | Lw : ElemUnit Length 221 | Lw = LightWeek 222 | 223 | LightYear : ElemUnit Length 224 | LightYear = < one "ly" equals 1 (Year <**> SpeedOfLight) > 225 | Ly : ElemUnit Length 226 | Ly = LightYear 227 | 228 | 229 | -- Non-SI units associated with the CGS and the CGS-Gaussian system of units 230 | 231 | Erg : Unit Energy 232 | Erg = Ten ^^ -7 <**> Joule 233 | 234 | Dyne : Unit Force' 235 | Dyne = Ten ^^ -5 <**> Newton 236 | Dyn : Unit Force' 237 | Dyn = Dyne 238 | 239 | Poise : Unit DynamicViscosity 240 | Poise = Dyne <**> Second (Centimetre ^^ 2) 241 | P : Unit DynamicViscosity 242 | P = Poise 243 | 244 | Stokes : Unit KinematicViscosity 245 | Stokes = Centimetre ^^ 2 Second 246 | St : Unit KinematicViscosity 247 | St = Stokes 248 | 249 | Stilb : Unit Luminance 250 | Stilb = Candela (Centimetre ^^ 2) 251 | Sb : Unit Luminance 252 | Sb = Stilb 253 | 254 | Phot : Unit Illuminance 255 | Phot = Candela <**> Steradian (Centimetre ^^ 2) 256 | Ph : Unit Illuminance 257 | Ph = Phot 258 | 259 | Gal : Unit Acceleration 260 | Gal = Centimetre (Second ^^ 2) 261 | 262 | Maxwell : Unit MagneticFlux 263 | Maxwell = Ten ^^ -8 <**> Weber 264 | Mx : Unit MagneticFlux 265 | Mx = Maxwell 266 | 267 | Gauss : Unit MagneticFluxDensity 268 | Gauss = Maxwell (Centimetre ^^ 2) 269 | G : Unit MagneticFluxDensity 270 | G = Gauss 271 | 272 | Oersted : ElemUnit MagneticFieldStrength 273 | Oersted = < one "oe" equals (250 / pi) (Ampere Metre) > 274 | Oe : ElemUnit MagneticFieldStrength 275 | Oe = Oersted -------------------------------------------------------------------------------- /Quantities/Power.idr: -------------------------------------------------------------------------------- 1 | module Quantities.Power 2 | 3 | --import Control.Algebra 4 | 5 | infixr 10 ^ 6 | 7 | %default total 8 | %access public export 9 | 10 | 11 | -- 'Group', '<->' and 'AbelianGroup' are copied from Control.Algebra from 'contrib'. 12 | -- I didn't just include Control.Algebra, because 'idris --install quantities.ipkg' 13 | -- didn't know where to find Control.Algebra. Specifying 'contrib' in libs in 14 | -- the IPKG file didn't help either. 15 | 16 | -- XXX: change? 17 | infixl 6 <-> 18 | 19 | ||| Sets equipped with a single binary operation that is associative, along with 20 | ||| a neutral element for that binary operation and inverses for all elements. 21 | ||| Must satisfy the following laws: 22 | ||| + Associativity of `<+>`: 23 | ||| forall a b c, a <+> (b <+> c) == (a <+> b) <+> c 24 | ||| + Neutral for `<+>`: 25 | ||| forall a, a <+> neutral == a 26 | ||| forall a, neutral <+> a == a 27 | ||| + Inverse for `<+>`: 28 | ||| forall a, a <+> inverse a == neutral 29 | ||| forall a, inverse a <+> a == neutral 30 | interface Monoid a => Group a where 31 | inverse : a -> a 32 | 33 | (<->) : Group a => a -> a -> a 34 | (<->) left right = left <+> (inverse right) 35 | 36 | interface Group a => AbelianGroup a where { } 37 | 38 | public export 39 | interface Power a where 40 | (^) : a -> Integer -> a 41 | 42 | interface Power a => VerifiedPower a where 43 | iteratedPower : (x : a) -> (i : Integer) -> (j : Integer) -> 44 | (x ^ i) ^ j = x ^ (i*j) 45 | 46 | -- Inefficient. Use square and multiply! 47 | grpPow : Group g => g -> g -> Nat -> g 48 | grpPow _ y Z = y 49 | grpPow x y (S k) = grpPow x (y <+> x) k 50 | 51 | implementation Group g => Power g where 52 | (^) a i = case compare i 0 of 53 | LT => grpPow (inverse a) neutral (fromIntegerNat (-i)) 54 | _ => grpPow a neutral (fromIntegerNat i) 55 | 56 | implementation [floatmultpower] Power Double where 57 | a ^ 0 = fromInteger 1 58 | a ^ i = if a == 0 then 0 else case compare i 0 of 59 | LT => pow (1 / a) (fromIntegerNat (-i)) 60 | _ => pow a (fromIntegerNat i) 61 | -------------------------------------------------------------------------------- /Quantities/SIBaseQuantities.idr: -------------------------------------------------------------------------------- 1 | module Quantities.SIBaseQuantities 2 | 3 | import Quantities.Core 4 | 5 | %default total 6 | %access public export 7 | 8 | Length : Dimension 9 | Length = MkDimension "Length" 10 | 11 | Mass : Dimension 12 | Mass = MkDimension "Mass" 13 | 14 | Time : Dimension 15 | Time = MkDimension "Time" 16 | 17 | ElectricCurrent : Dimension 18 | ElectricCurrent = MkDimension "ElectricCurrent" 19 | 20 | -- Thermodynamic temperature 21 | Temperature : Dimension 22 | Temperature = MkDimension "Temperature" 23 | 24 | AmountOfSubstance : Dimension 25 | AmountOfSubstance = MkDimension "AmountOfSubstance" 26 | 27 | LuminousIntensity : Dimension 28 | LuminousIntensity = MkDimension "LuminousIntensity" 29 | -------------------------------------------------------------------------------- /Quantities/SIBaseUnits.idr: -------------------------------------------------------------------------------- 1 | module Quantities.SIBaseUnits 2 | 3 | import Quantities.Core 4 | import Quantities.SIPrefixes 5 | import Quantities.SIBaseQuantities 6 | 7 | %default total 8 | %access public export 9 | 10 | Metre : ElemUnit Length 11 | Metre = MkElemUnit "m" 1 12 | Meter : ElemUnit Length 13 | Meter = Metre 14 | M : ElemUnit Length 15 | M = Meter 16 | 17 | Centimetre : Unit Length 18 | Centimetre = centi Metre 19 | Centimeter : Unit Length 20 | Centimeter = Centimetre 21 | Cm : Unit Length 22 | Cm = Centimetre 23 | 24 | Kilometre : Unit Length 25 | Kilometre = kilo Metre 26 | Kilometer : Unit Length 27 | Kilometer = Kilometre 28 | Km : Unit Length 29 | Km = Kilometre 30 | 31 | Gram : ElemUnit Mass 32 | Gram = MkElemUnit "g" 0.001 33 | G : ElemUnit Mass 34 | G = Gram 35 | 36 | Kilogram : Unit Mass 37 | Kilogram = kilo Gram 38 | Kg : Unit Mass 39 | Kg = Kilogram 40 | 41 | Second : ElemUnit Time 42 | Second = MkElemUnit "s" 1 43 | S : ElemUnit Time 44 | S = Second 45 | 46 | Ampere : ElemUnit ElectricCurrent 47 | Ampere = MkElemUnit "A" 1 48 | A : ElemUnit ElectricCurrent 49 | A = Ampere 50 | 51 | Kelvin : ElemUnit Temperature 52 | Kelvin = MkElemUnit "K" 1 53 | K : ElemUnit Temperature 54 | K = Kelvin 55 | 56 | Mole : ElemUnit AmountOfSubstance 57 | Mole = MkElemUnit "mol" 1 58 | Mol : ElemUnit AmountOfSubstance 59 | Mol = Mole 60 | 61 | Candela : ElemUnit LuminousIntensity 62 | Candela = MkElemUnit "cd" 1 63 | Cd : ElemUnit LuminousIntensity 64 | Cd = Candela 65 | -------------------------------------------------------------------------------- /Quantities/SIDerivedQuantities.idr: -------------------------------------------------------------------------------- 1 | module Quantities.SIDerivedQuantities 2 | 3 | import Quantities.Core 4 | import Quantities.SIBaseQuantities 5 | 6 | %default total 7 | %access public export 8 | 9 | 10 | -- Examples of coherent derived units in the SI expressed in terms of base 11 | -- units 12 | 13 | Area : Quantity 14 | Area = Length ^ 2 15 | 16 | Volume : Quantity 17 | Volume = Length ^ 3 18 | 19 | Speed : Quantity 20 | Speed = Length Time 21 | 22 | Velocity : Quantity 23 | Velocity = Speed 24 | 25 | Acceleration : Quantity 26 | Acceleration = Speed Time 27 | 28 | Wavenumber : Quantity 29 | Wavenumber = Length ^ (-1) 30 | 31 | Density : Quantity 32 | Density = Mass Volume 33 | 34 | MassDensity : Quantity 35 | MassDensity = Density 36 | 37 | SurfaceDensity : Quantity 38 | SurfaceDensity = Mass Area 39 | 40 | SpecificVolume : Quantity 41 | SpecificVolume = Volume Mass 42 | 43 | CurrentDensity : Quantity 44 | CurrentDensity = ElectricCurrent Area 45 | 46 | MagneticFieldStrength : Quantity 47 | MagneticFieldStrength = ElectricCurrent Length 48 | 49 | AmountConcentration : Quantity 50 | AmountConcentration = AmountOfSubstance Volume 51 | 52 | Concentration : Quantity 53 | Concentration = AmountConcentration 54 | 55 | MassConcentration : Quantity 56 | MassConcentration = Mass Volume 57 | 58 | Luminance : Quantity 59 | Luminance = LuminousIntensity Area 60 | 61 | RefractiveIndex : Quantity 62 | RefractiveIndex = Scalar 63 | 64 | RelativePermeability : Quantity 65 | RelativePermeability = Scalar 66 | 67 | 68 | -- Coherent derived units in the SI with special names and symbols 69 | 70 | PlaneAngle : Quantity 71 | PlaneAngle = Scalar 72 | 73 | SolidAngle : Quantity 74 | SolidAngle = Scalar 75 | 76 | Frequency : Quantity 77 | Frequency = Time ^ (-1) 78 | 79 | Force' : Quantity 80 | Force' = Acceleration <*> Mass 81 | 82 | Pressure : Quantity 83 | Pressure = Force' Area 84 | 85 | Stress : Quantity 86 | Stress = Pressure 87 | 88 | Energy : Quantity 89 | Energy = Force' <*> Length 90 | 91 | Work : Quantity 92 | Work = Energy 93 | 94 | AmountOfHeat : Quantity 95 | AmountOfHeat = Energy 96 | 97 | Power : Quantity 98 | Power = Energy Time 99 | 100 | RadiantFlux : Quantity 101 | RadiantFlux = Power 102 | 103 | ElectricCharge : Quantity 104 | ElectricCharge = Time <*> ElectricCurrent 105 | 106 | AmountOfElectricity : Quantity 107 | AmountOfElectricity = ElectricCharge 108 | 109 | ElectricPotentialDifference : Quantity 110 | ElectricPotentialDifference = Power ElectricCurrent 111 | 112 | ElectromotiveForce : Quantity 113 | ElectromotiveForce = ElectricPotentialDifference 114 | 115 | Capacitance : Quantity 116 | Capacitance = ElectricCharge ElectricPotentialDifference 117 | 118 | ElectricResistance : Quantity 119 | ElectricResistance = ElectricPotentialDifference ElectricCurrent 120 | 121 | ElectricConductance : Quantity 122 | ElectricConductance = ElectricCurrent ElectricPotentialDifference 123 | 124 | MagneticFlux : Quantity 125 | MagneticFlux = Time <*> ElectricPotentialDifference 126 | 127 | MagneticFluxDensity : Quantity 128 | MagneticFluxDensity = MagneticFlux Area 129 | 130 | Inductance : Quantity 131 | Inductance = MagneticFlux ElectricCurrent 132 | 133 | -- Celsius temperature 134 | 135 | LuminousFlux : Quantity 136 | LuminousFlux = LuminousIntensity <*> SolidAngle 137 | 138 | Illuminance : Quantity 139 | Illuminance = LuminousFlux Area 140 | 141 | ActivityReferredToARadionuclide : Quantity 142 | ActivityReferredToARadionuclide = Time ^ (-1) 143 | 144 | -- ... sometimes incorrectly called 145 | Radioactivity : Quantity 146 | Radioactivity = ActivityReferredToARadionuclide 147 | 148 | AbsorbedDose : Quantity 149 | AbsorbedDose = Energy Mass 150 | 151 | SpecificEnergy : Quantity 152 | SpecificEnergy = AbsorbedDose 153 | 154 | Kerma : Quantity 155 | Kerma = AbsorbedDose 156 | 157 | DoseEquivalent : Quantity 158 | DoseEquivalent = Energy Mass 159 | 160 | AmbientDoseEquivalent : Quantity 161 | AmbientDoseEquivalent = DoseEquivalent 162 | 163 | DirectionalDoseEquivalent : Quantity 164 | DirectionalDoseEquivalent = DoseEquivalent 165 | 166 | PersonalDoseEquivalent : Quantity 167 | PersonalDoseEquivalent = DoseEquivalent 168 | 169 | CatalyticActivity : Quantity 170 | CatalyticActivity = AmountOfSubstance Time 171 | 172 | 173 | -- Examples of SI coherent derived units whose names and symbols include SI 174 | -- coherent derived units with special names and symbols 175 | 176 | DynamicViscosity : Quantity 177 | DynamicViscosity = Stress <*> Time 178 | 179 | KinematicViscosity : Quantity 180 | KinematicViscosity = Area Time 181 | 182 | MomentOfForce : Quantity 183 | MomentOfForce = Force' <*> Length 184 | 185 | Moment : Quantity 186 | Moment = MomentOfForce 187 | 188 | Torque : Quantity 189 | Torque = MomentOfForce 190 | 191 | SurfaceTension : Quantity 192 | SurfaceTension = Force' Length 193 | 194 | AngularVelocity : Quantity 195 | AngularVelocity = PlaneAngle Time 196 | 197 | AngularAcceleration : Quantity 198 | AngularAcceleration = AngularVelocity Time 199 | 200 | HeatFluxDensity : Quantity 201 | HeatFluxDensity = Power Area 202 | 203 | Irradiance : Quantity 204 | Irradiance = HeatFluxDensity 205 | 206 | HeatCapacity : Quantity 207 | HeatCapacity = Energy Temperature 208 | 209 | Entropy : Quantity 210 | Entropy = HeatCapacity 211 | 212 | SpecificHeatCapacity : Quantity 213 | SpecificHeatCapacity = HeatCapacity Mass 214 | 215 | SpecificEntropy : Quantity 216 | SpecificEntropy = Entropy Mass 217 | 218 | ThermalConductivity : Quantity 219 | ThermalConductivity = Power (Length <*> Temperature) 220 | 221 | EnergyDensity : Quantity 222 | EnergyDensity = Energy Volume 223 | 224 | ElectricFieldStrength : Quantity 225 | ElectricFieldStrength = ElectricPotentialDifference Length 226 | 227 | ElectricChargeDensity : Quantity 228 | ElectricChargeDensity = ElectricCharge Volume 229 | 230 | SurfaceChargeDensity : Quantity 231 | SurfaceChargeDensity = ElectricCharge Area 232 | 233 | ElectricFluxDensity : Quantity 234 | ElectricFluxDensity = SurfaceChargeDensity 235 | 236 | ElectricDisplacement : Quantity 237 | ElectricDisplacement = SurfaceChargeDensity 238 | 239 | Permettivity : Quantity 240 | Permettivity = Capacitance Length 241 | 242 | Permeability : Quantity 243 | Permeability = Inductance Length 244 | 245 | MolarEnergy : Quantity 246 | MolarEnergy = Energy AmountOfSubstance 247 | 248 | MolarHeatCapacity : Quantity 249 | MolarHeatCapacity = MolarEnergy 250 | 251 | Exposure : Quantity 252 | Exposure = ElectricCharge Mass 253 | 254 | AbsorbedDoseRate : Quantity 255 | AbsorbedDoseRate = AbsorbedDose Time 256 | 257 | RadiantIntensity : Quantity 258 | RadiantIntensity = Power SolidAngle 259 | 260 | Radiance : Quantity 261 | Radiance = RadiantIntensity Area 262 | 263 | CatalyticActivityConcentration : Quantity 264 | CatalyticActivityConcentration = CatalyticActivity Volume 265 | -------------------------------------------------------------------------------- /Quantities/SIDerivedUnits.idr: -------------------------------------------------------------------------------- 1 | module Quantities.Units 2 | 3 | import Quantities.Core 4 | import Quantities.SIBaseQuantities 5 | import Quantities.SIDerivedQuantities 6 | import Quantities.SIBaseUnits 7 | 8 | %default total 9 | %access public export 10 | 11 | Radian : Unit PlaneAngle 12 | Radian = One 13 | Rad : Unit PlaneAngle 14 | Rad = One 15 | 16 | Steradian : Unit SolidAngle 17 | Steradian = One 18 | Sr : Unit SolidAngle 19 | Sr = Steradian 20 | 21 | Hertz : Unit Frequency 22 | Hertz = Second ^^ (-1) 23 | Hz : Unit Frequency 24 | Hz = Hertz 25 | 26 | Newton : Unit Force' 27 | Newton = ((Metre Second) Second) <**> Kilogram 28 | N : Unit Force' 29 | N = Newton 30 | 31 | Pascal : Unit Pressure 32 | Pascal = Newton (Metre ^^ 2) 33 | Pa : Unit Pressure 34 | Pa = Pascal 35 | 36 | Joule : Unit Energy 37 | Joule = Newton <**> Metre 38 | J : Unit Energy 39 | J = Joule 40 | 41 | Watt : Unit Power 42 | Watt = Joule Second 43 | W : Unit Power 44 | W = Watt 45 | 46 | Coulomb : Unit ElectricCharge 47 | Coulomb = Second <**> Ampere 48 | C : Unit ElectricCharge 49 | C = Coulomb 50 | 51 | Volt : Unit ElectricPotentialDifference 52 | Volt = Watt Ampere 53 | V : Unit ElectricPotentialDifference 54 | V = Volt 55 | 56 | Farad : Unit Capacitance 57 | Farad = Coulomb Volt 58 | F : Unit Capacitance 59 | F = Farad 60 | 61 | Ohm : Unit ElectricResistance 62 | Ohm = Volt Ampere 63 | 64 | Siemens : Unit ElectricConductance 65 | Siemens = Ampere Volt 66 | S : Unit ElectricConductance 67 | S = Siemens 68 | 69 | Weber : Unit MagneticFlux 70 | Weber = Second <**> Volt 71 | Wb : Unit MagneticFlux 72 | Wb = Weber 73 | 74 | Tesla : Unit MagneticFluxDensity 75 | Tesla = Weber (Metre ^^ 2) 76 | T : Unit MagneticFluxDensity 77 | T = Tesla 78 | 79 | Henry : Unit Inductance 80 | Henry = Weber Ampere 81 | H : Unit Inductance 82 | H = Henry 83 | 84 | -- For relative temperature measurements 85 | Celsius : Unit Temperature 86 | Celsius = Kelvin 87 | DC : Unit Temperature 88 | DC = Celsius 89 | 90 | Lumen : Unit LuminousFlux 91 | Lumen = Candela <**> Steradian 92 | Lm : Unit LuminousFlux 93 | Lm = Lumen 94 | 95 | Lux : Unit Illuminance 96 | Lux = Lumen (Metre ^^ 2) 97 | Lx : Unit Illuminance 98 | Lx = Lux 99 | 100 | Becquerel : Unit ActivityReferredToARadionuclide 101 | Becquerel = Second ^^ (-1) 102 | Bq : Unit ActivityReferredToARadionuclide 103 | Bq = Becquerel 104 | 105 | Gray : Unit AbsorbedDose 106 | Gray = Joule Kilogram 107 | Gy : Unit AbsorbedDose 108 | Gy = Gray 109 | 110 | Sievert : Unit DoseEquivalent 111 | Sievert = Joule Kilogram 112 | Sv : Unit DoseEquivalent 113 | Sv = Sievert 114 | 115 | Katal : Unit CatalyticActivity 116 | Katal = Mol Second 117 | Kat : Unit CatalyticActivity 118 | Kat = Katal 119 | -------------------------------------------------------------------------------- /Quantities/SIPrefixes.idr: -------------------------------------------------------------------------------- 1 | module Quantities.SIPrefixes 2 | 3 | import Quantities.Core 4 | 5 | %default total 6 | %access public export 7 | 8 | makePrefix : Integer -> Unit q -> Unit q 9 | makePrefix i (MkUnit e us) = MkUnit (e+i) us 10 | 11 | 12 | -- List of prefixes from 13 | -- http://en.wikipedia.org/wiki/Metric_prefix 14 | 15 | yotta : Unit q -> Unit q 16 | yotta = makePrefix 24 17 | 18 | zetta : Unit q -> Unit q 19 | zetta = makePrefix 21 20 | 21 | exa : Unit q -> Unit q 22 | exa = makePrefix 18 23 | 24 | peta : Unit q -> Unit q 25 | peta = makePrefix 15 26 | 27 | tera : Unit q -> Unit q 28 | tera = makePrefix 12 29 | 30 | giga : Unit q -> Unit q 31 | giga = makePrefix 9 32 | G : Unit q -> Unit q 33 | G = giga 34 | 35 | mega : Unit q -> Unit q 36 | mega = makePrefix 6 37 | M : Unit q -> Unit q 38 | M = mega 39 | 40 | kilo : Unit q -> Unit q 41 | kilo = makePrefix 3 42 | k : Unit q -> Unit q 43 | k = kilo 44 | 45 | hecto : Unit q -> Unit q 46 | hecto = makePrefix 2 47 | 48 | deca : Unit q -> Unit q 49 | deca = makePrefix 1 50 | da : Unit q -> Unit q 51 | da = deca 52 | 53 | -- ################## -- 54 | 55 | deci : Unit q -> Unit q 56 | deci = makePrefix (-1) 57 | 58 | centi : Unit q -> Unit q 59 | centi = makePrefix (-2) 60 | 61 | milli : Unit q -> Unit q 62 | milli = makePrefix (-3) 63 | 64 | micro : Unit q -> Unit q 65 | micro = makePrefix (-6) 66 | 67 | nano : Unit q -> Unit q 68 | nano = makePrefix (-9) 69 | 70 | pico : Unit q -> Unit q 71 | pico = makePrefix (-12) 72 | 73 | femto : Unit q -> Unit q 74 | femto = makePrefix (-15) 75 | 76 | atto : Unit q -> Unit q 77 | atto = makePrefix (-18) 78 | 79 | zepto : Unit q -> Unit q 80 | zepto = makePrefix (-21) 81 | 82 | yocto : Unit q -> Unit q 83 | yocto = makePrefix (-24) 84 | -------------------------------------------------------------------------------- /Quantities/Screen.idr: -------------------------------------------------------------------------------- 1 | module Quantities.Screen 2 | 3 | import Quantities.Core 4 | import Quantities.SIBaseQuantities 5 | import Quantities.ImperialUnits 6 | import Quantities.SIBaseUnits 7 | 8 | %default total 9 | %access public export 10 | 11 | ScreenLength : Dimension 12 | ScreenLength = MkDimension "ScreenLength" 13 | 14 | Pixel : ElemUnit ScreenLength 15 | Pixel = MkElemUnit "px" 1 16 | Px : ElemUnit ScreenLength 17 | Px = Pixel 18 | 19 | ScreenArea : Quantity 20 | ScreenArea = ScreenLength ^ 2 21 | ScreenEstate : Quantity 22 | ScreenEstate = ScreenArea 23 | 24 | ScreenResolution : Quantity 25 | ScreenResolution = ScreenLength Length 26 | 27 | PixelPerCentimetre : ElemUnit ScreenResolution 28 | PixelPerCentimetre = < one "ppcm" equals 1 (Pixel Centimetre) > 29 | PixelPerCentimeter : ElemUnit ScreenResolution 30 | PixelPerCentimeter = PixelPerCentimetre 31 | Ppcm : ElemUnit ScreenResolution 32 | Ppcm = PixelPerCentimetre 33 | 34 | PixelPerInch : ElemUnit ScreenResolution 35 | PixelPerInch = < one "ppi" equals 1 (Pixel Inch) > 36 | Ppi : ElemUnit ScreenResolution 37 | Ppi = PixelPerInch 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Quantities [![Build Status](https://travis-ci.org/timjb/quantities.svg?branch=master)](https://travis-ci.org/timjb/quantities) 2 | 3 | Quantities is a library for type-safe physical computations and unit conversions in Idris. 4 | 5 |

6 | New Cuyama 7 |

8 | 9 | ([Population Explosion!](http://www.flickr.com/photos/7-how-7/4139229048/in/photolist-7iLCA5-7k6s5z-7kan7d-9qNAwp-byuLp3-byuL93-7LTGBJ-9qNAMV-7LRM7r-hUvGJ3-7LK1as-7LJRRh-7LJZuN-7LF4UF-7LK2q5-7LTL3L-7LF2VD-7LJSsf-7LLNXx-7LQL5A-7LQMJY-7LTFgo-7LLLya-7LPJ4n-7LTEAJ-7LLMVX-7LRLu4-7RxVet-7Q9PPZ-7LLM2P-7LMFkF-7LRPFK-7LTJEN-7LNtL6-7LRAjs-7LLL6V-7LSqZJ-7LVMcC-7LRMNa-7LNsda-7LMzHt-7LMApk-7LTDZ9-7LRKHH-7LQK77-7LMBKH-7LRNtX-7QX1rM-7RxV5p-7QX1sx-7LRB1J/) by [7-how-7](http://www.flickr.com/photos/7-how-7/) – sign first seen on Andrew Kennedy's [Units-of-Measure page](http://research.microsoft.com/en-us/um/people/akenn/units/)) 10 | 11 | I'm collecting links on types and units of measures in the [wiki](https://github.com/timjb/quantities/wiki/Links). If you know an interesting project, paper etc. you're invited to add it to the list! 12 | 13 | ## Installation 14 | 15 | Copy this package and run 16 | 17 | ```bash 18 | $ idris --install quantities.ipkg 19 | ``` 20 | To use it in your program, run Idris with 21 | 22 | ```bash 23 | $ idris -p quantities yourprogram.idr 24 | ``` 25 | 26 | **Compatibility: Tested with Idris 1.3.1** 27 | 28 | ## Documentation 29 | 30 | ### Quantities 31 | 32 | Quantities are physical properties that you can measure. They include length, speed, pressure, electric resistance, etc. We can multiply and divide quantities to form new quantities: 33 | 34 | ```idris 35 | Area : Quantity 36 | Area = Length <*> Length 37 | 38 | Speed : Quantity 39 | Speed = Length Time 40 | 41 | Volume : Quantity 42 | Volume = Length ^ 3 43 | 44 | Frequency : Quantity 45 | Frequency = Time ^ (-1) 46 | ``` 47 | 48 | Above we defined the quantities `Area`, `Speed`, `Volume` and `Frequency` in terms of `Length` and `Time`. By convention, we write quantities with capital letters. 49 | 50 | 51 | ### Dimensions 52 | 53 | Of course, we can't derive all quantities from existing quantities, but have to start with some base quantities. The SI system of units defines `Length`, `Mass`, `Time`, `ElectricCurrent`, `Temperature`, `AmountOfSubstance` and `LuminousIntensity` as base quantities. We can declare them like this: 54 | 55 | ```idris 56 | Length : Dimension 57 | Length = MkDimension "Length" 58 | 59 | Time : Dimension 60 | Time = MkDimension "Time" 61 | 62 | Happiness : Dimension 63 | Happiness = MkDimension "Happiness" 64 | ``` 65 | 66 | The `Quantity` data type is now defined as the [free abelian group](http://en.wikipedia.org/wiki/Free_abelian_group) over the `Dimension` data type. There is a function, `dimensionToQuantity : Dimension -> Quantity`, which implicitly converts dimensions to quantities. 67 | 68 | 69 | ### Units 70 | 71 | A unit represents a specific amount of a quantity. For example, we have 72 | 73 | ```idris 74 | Centimetre : Unit Length 75 | Second : Unit Time 76 | Ampere : Unit ElectricCurrent 77 | Newton : Unit Force 78 | ``` 79 | 80 | Notice that units are indexed by the quantity they represent. Like with quantities, we can multiply and devide units to derive new units. But there is a catch: when we multiply two units, the resulting unit represents the product of their respective quantities. For example, when we multiply the unit `Centimetre` with itself, we get a unit for area, since `Area = Length <*> Length`. Therefore, we have the functions 81 | 82 | ```idris 83 | (<**>) : {q : Quantity} -> {r : Quantity} -> Unit q -> Unit r -> Unit (q <*> r) 84 | () : {q : Quantity} -> {r : Quantity} -> Unit q -> Unit r -> Unit (q r) 85 | (^^) : {q : Quantity} -> Unit r -> (i : Integer) -> Unit (q ^ i) 86 | ``` 87 | 88 | For example: 89 | 90 | ```idris 91 | SquareCentimetre : Unit Area 92 | SquareCentimetre = Centimetre <**> Centimetre -- = Centimetre ^^ 2 93 | 94 | MetrePerSecond : Unit Speed 95 | MetrePerSecond = Meter Second 96 | 97 | CubicCentimetre : Unit Volume 98 | CubicCentimetre = Centimetre ^^ 3 99 | 100 | Newton : Unit ((Length <*> Mass) (Time ^ 2)) 101 | Newton = (Metre <**> Kilogram) (Second ^^ 2) 102 | ``` 103 | 104 | 105 | ### Elementary Units 106 | 107 | We have to start somewhere by defining some base units: 108 | 109 | ```idris 110 | Metre : ElemUnit Length 111 | Metre = MkElemUnit "m" 1 112 | 113 | Second : ElemUnit Time 114 | Second = MkElemUnit "s" 1 115 | 116 | Candela : ElemUnit LuminousIntensity 117 | Candela = MkElemUnit "cd" 1 118 | 119 | -- the quantity of happiness that a one kilogram beagle puppy whose body temperature is 310 kelvins produces when held in skin contact for one second 120 | Puppy : ElemUnit Happiness 121 | Puppy = MkElemUnit "puppy" 1 122 | ``` 123 | 124 | These are called elementary units. The number at the end of `MkElemUnit` is the conversion rate to the base unit of the quantity. Since `Metre`, `Candela` and `Puppy` are the base units themselves, the conversion rate for them is `1`. Which unit you consider as a base unit for a dimension isn't important as long as you stay consistent with your choices. 125 | 126 | Elementary units are not just a way to bootstrap the system of units; they can also be used to define other units, with some syntax sugar: 127 | 128 | ```idris 129 | Mile : ElemUnit Length 130 | Mile = < one "mile" equals 1609.344 Metre > 131 | 132 | -- Speed of light 133 | C_0 : ElemUnit Speed 134 | C_0 = < one "c_0" equals 299792458 (Metre Second) > 135 | 136 | -- If you're like me ... 137 | Kitten : ElemUnit Happiness 138 | Kitten = < one "kitten" equals 1.5 Puppy > 139 | ``` 140 | 141 | Units are defined as the free abelian group over elementary units, with the addition that we keep track of the quantities that are represented by the units. 142 | 143 | Elementary units are implicitly converted to units by the function 144 | 145 | ```idris 146 | elemUnitToUnit : {q : Quantity} -> ElemUnit q -> Unit q 147 | ``` 148 | 149 | 150 | ### Measurements 151 | 152 | Measurements are values tagged with a unit. 153 | 154 | ```idris 155 | data Measurement : {q : Quantity} -> Unit q -> Type -> Type where 156 | (=|) : a -> (u : Unit q) -> Measurement u a 157 | ``` 158 | 159 | Since `Measurement` is a bit long, there is a shorthand form: `u :| a` is the same as `Measurement u a`. For measurements with float values there is an even shorter alias: 160 | 161 | ```idris 162 | F : Unit q -> Type 163 | F u = Measurement u Float 164 | ``` 165 | 166 | For example: 167 | 168 | ```idris 169 | distanceToMoon : F Metre 170 | distanceToMoon = 384400000.0 =| Metre 171 | ``` 172 | 173 | 174 | ### Converting between units 175 | 176 | Sometimes, a conversion isn't necessary. For example, the unit `Newton` is definitionally equal to `(Metre <**> Kilogram) (Second ^^ 2)`, so you won't have to convert between these. But generally, you will need a conversion function. 177 | 178 | ```idris 179 | distanceToMoonInMiles : F miles 180 | distanceToMoonInMiles = convertTo Mile distanceToMoon 181 | 182 | -- According to Wikipedia 183 | DogYear : ElemUnit Time 184 | DogYear = < one "dy" equals 52 Day > 185 | 186 | myAgeInDogYears : F DogYear 187 | myAgeInDogYears = (21 =| Year) `as` DogYear 188 | ``` 189 | 190 | Since the target unit in the first example is clear from the context, we could write `convert` instead of `convertTo Mile`. For reference, the conversion functions used above are 191 | 192 | ```idris 193 | convertTo : {from : Unit q} -> (to : Unit q) -> F from -> F to 194 | convert : {from : Unit q} -> {to : Unit q} -> F from -> F to 195 | as : {from : Unit q} -> F from -> (to : Unit q) -> F to 196 | ``` 197 | 198 | 199 | ### Calculations with measurements 200 | 201 | Let's say I've lifted a 5 kg weight from ground to a height of 2 metre in 0.8 seconds. What's the average power of this action? 202 | 203 | ```idris 204 | weight : F Kilogram 205 | weight = 2 =| Kilogram 206 | 207 | height : F Metre 208 | height = 2 =| Metre 209 | 210 | duration : F Second 211 | duration = 0.8 =| Second 212 | 213 | g_0 : F (Metre (Second ^^ 2)) 214 | g_0 = 9.80665 =| (Metre (Second ^^ 2)) 215 | 216 | averagePower : F Watt 217 | averagePower = convert $ (weight |*| height |*| g_0) |/| duration 218 | -- = 49.033 Watt 219 | ``` 220 | 221 | This example shows how to multiply measurements using the functions 222 | 223 | ```idris 224 | (|*|) : Num a => {u : Unit q} -> {v : Unit r} -> u :| a -> v :| a -> (u <**> v) :| a 225 | (|/|) : {u : Unit q} -> {v : Unit r} -> F u -> F v -> F (u v) 226 | (|^|) : {u : Unit q} -> F u -> (i : Integer) -> F (u ^^ i) 227 | ``` 228 | 229 | We can even use these functions to multiply measurements with scalar values: 230 | 231 | ```idris 232 | energyConversionEfficiency : F One 233 | energyConversionEfficiency = 0.88 =| One 234 | 235 | batteryCapacity : F (Watt <**> Hour) 236 | batteryCapacity = 85000 =| (Watt <**> Hour) 237 | 238 | usedEnergy : F (Watt <**> Hour) 239 | usedEnergy = convert $ energyConversionEfficiency |*| batteryCapacity 240 | ``` 241 | 242 | We can add and subtract measurements, too, but only if they have the same unit: 243 | 244 | ```idris 245 | (<+>) : Num a => Measurement u a -> Measurement u a -> Measurement u a 246 | (<->) : Num a => Measurement u a -> Measurement u a -> Measurement u a 247 | ``` 248 | 249 | For example: 250 | 251 | ```idris 252 | eatChocolateCake : F Puppy -> F Puppy 253 | eatChocolateCake x = x <+> (2 =| Puppy) 254 | ``` 255 | 256 | 257 | ### Predefined quantities and units 258 | 259 | The library comes with many quantities and units predefined. 260 | 261 | From the [International System of Units (SI)](http://en.wikipedia.org/wiki/International_System_of_Units): 262 | 263 | * [`Quantities.SIBaseQuantities`](https://github.com/timjb/quantities/blob/master/Quantities/SIBaseQuantities.idr): The seven SI base quantities `Length`, `Mass`, `Time`, `ElectricCurrent`, `Temperature`, `LuminousIntensity` and `AmountOfSubstance` 264 | * [`Quantities.SIDerivedQuantities`](https://github.com/timjb/quantities/blob/master/Quantities/SIDerivedQuantities.idr): SI derived quantites, e.g. `Velocity`, `Acceleration`, `ElectricResistance`, `Energy`, etc. 265 | * [`Quantities.SIBaseUnits`](https://github.com/timjb/quantities/blob/master/Quantities/SIBaseUnits.idr): The base units corresponding to the base quantities: `Meter`, `Kilogram`, `Second`, `Ampere`, `Kelvin`, `Candela` and `Mole` 266 | * [`Quantities.SIDerivedUnits`](https://github.com/timjb/quantities/blob/master/Quantities/SIDerivedUnits.idr): Various units derived from the seven base units, e.g. `Joule`, `Pascal`, `Ohm`, `Hertz` 267 | 268 | These four modules are reexported by the main module [`Quantities`](https://github.com/timjb/quantities/blob/master/Quantities.idr). 269 | 270 | Other quantities and units: 271 | 272 | * [`Quantities.ImperialUnits`](https://github.com/timjb/quantities/blob/master/Quantities/ImperialUnits.idr): Imperial units, e.g. `Mile`, `Inch`, `Gallon`, `Pound` 273 | * [`Quantities.NonSIUnits`](https://github.com/timjb/quantities/blob/master/Quantities/NonSIUnits.idr): Various common and uncommon units, e.g. `Minute`, `Electronvolt`, `Calorie`, `Tonne`, `LightYear` 274 | * [`Quantities.Information`](https://github.com/timjb/quantities/blob/master/Quantities/Information.idr): Contains the quantity `Information` and its units `Bit` and `Bytes` with their various [binary prefixes](http://en.wikipedia.org/wiki/Binary_prefix), e.g. `mebi Byte` for 1024^2 bytes. 275 | * [`Quantities.Screen`](https://github.com/timjb/quantities/blob/master/Quantities/Screen.idr): The quantity `ScreenLength` with the unit `Pixel`. Useful for UI programming. 276 | 277 | 278 | ### Metric Prefixes 279 | 280 | All standard [SI prefixes](http://en.wikipedia.org/wiki/Metric_prefix) are supported. For example: 281 | 282 | ```idris 283 | import Quantities 284 | 285 | microscopeResolution : F (nano Metre) 286 | microscopeResolution = 180 =| (nano Metre) 287 | 288 | performance : F (mega Watt) 289 | performance = 3.1 =| (mega Watt) 290 | ``` 291 | 292 | 293 | ## Example 294 | 295 | A simple example that demonstrates how one could use quantities to implement simple movement with gravity in a game. 296 | 297 | ```idris 298 | module Game 299 | 300 | import Quantities 301 | import Quantities.Screen 302 | 303 | ScreenSpeed : Quantity 304 | ScreenSpeed = ScreenLength Time 305 | 306 | Pxs : Unit ScreenSpeed 307 | Pxs = Pixel Second 308 | 309 | record PlayerState where 310 | constructor MkPlayerState 311 | xSpeed : F Pxs 312 | ySpeed : F Pxs 313 | xPos : F Px 314 | yPos : F Px 315 | 316 | gravity : Quantities.Core.F (Pxs Second) 317 | gravity = -800 =| (Pxs Second) 318 | 319 | -- Update player position and speed after a given duration 320 | updatePlayerState : F Second -> PlayerState -> PlayerState 321 | updatePlayerState dt (MkPlayerState xs ys xp yp) = 322 | let newYPos = yp <+> ys |*| dt 323 | in if newYPos <= (0 =| Px) 324 | then MkPlayerState (0 =| Pxs) (0 =| Pxs) xp (0 =| Px) 325 | else MkPlayerState xs (ys <+> gravity |*| dt) 326 | (xp <+> xs |*| dt) newYPos 327 | ``` 328 | 329 | ## Contributing 330 | 331 | Feedback and pull requests adding code and units are welcome! 332 | -------------------------------------------------------------------------------- /examples/Documentation.idr: -------------------------------------------------------------------------------- 1 | module Documentation 2 | 3 | import Quantities 4 | import Quantities.NonSIUnits 5 | import Quantities.ImperialUnits 6 | 7 | 8 | Happiness : Dimension 9 | Happiness = MkDimension "Happiness" 10 | 11 | cubicCentimetre : Unit Volume 12 | cubicCentimetre = Centimetre ^^ 3 13 | 14 | -- the quantity of happiness that a one kilogram beagle puppy whose body temperature is 310 kelvins produces when held in skin contact for one second 15 | Puppy : ElemUnit Happiness 16 | Puppy = MkElemUnit "puppy" 1 17 | 18 | -- If you're like me … 19 | Kitten : ElemUnit Happiness 20 | Kitten = < one "Kitten" equals 1.5 Puppy > 21 | 22 | distanceToMoon : F Metre 23 | distanceToMoon = 384400000.0 =| Metre 24 | 25 | distanceToMoonInMiles : F Mile 26 | distanceToMoonInMiles = convertTo Mile distanceToMoon 27 | 28 | -- According to Wikipedia 29 | DogYear : ElemUnit Time 30 | DogYear = < one "dy" equals 52 Day > 31 | 32 | myAgeInDogYears : F DogYear 33 | myAgeInDogYears = (21 =| Year) `as` DogYear 34 | -- = 133.46 dy 35 | 36 | weight : F Kilogram 37 | weight = 2 =| Kilogram 38 | 39 | height : F Metre 40 | height = 2 =| Metre 41 | 42 | duration : F Second 43 | duration = 0.8 =| Second 44 | 45 | g_0 : F (Metre (Second ^^ 2)) 46 | g_0 = 9.80665 =| (Metre (Second ^^ 2)) 47 | 48 | averagePower : F Watt 49 | averagePower = convert $ (weight |*| height |*| g_0) |/| duration 50 | 51 | energyConversionEfficiency : F One 52 | energyConversionEfficiency = 0.88 =| One 53 | 54 | batteryCapacity : F (Watt <**> Hour) 55 | batteryCapacity = 85000 =| (Watt <**> Hour) 56 | 57 | usedEnergy : F (Watt <**> Hour) 58 | usedEnergy = convert $ energyConversionEfficiency |*| batteryCapacity 59 | 60 | eatChocolateCake : F Puppy -> F Puppy 61 | eatChocolateCake x = x <+> (2 =| Puppy) 62 | 63 | microscopeResolution : F (nano Metre) 64 | microscopeResolution = 180 =| (nano Metre) 65 | 66 | performance : F (mega Watt) 67 | performance = 3.1 =| (mega Watt) 68 | -------------------------------------------------------------------------------- /examples/Game.idr: -------------------------------------------------------------------------------- 1 | module Game 2 | 3 | import Quantities 4 | import Quantities.Screen 5 | 6 | ScreenSpeed : Quantity 7 | ScreenSpeed = ScreenLength Time 8 | 9 | Pxs : Unit ScreenSpeed 10 | Pxs = Pixel Second 11 | 12 | record PlayerState where 13 | constructor MkPlayerState 14 | xSpeed : F Pxs 15 | ySpeed : F Pxs 16 | xPos : F Px 17 | yPos : F Px 18 | 19 | gravity : Quantities.Core.F (Pxs Second) 20 | gravity = -800 =| (Pxs Second) 21 | 22 | -- Update player position and speed after a given duration 23 | updatePlayerState : F Second -> PlayerState -> PlayerState 24 | updatePlayerState dt (MkPlayerState xs ys xp yp) = 25 | let newYPos = yp <+> ys |*| dt 26 | in if newYPos <= (0 =| Px) 27 | then MkPlayerState (0 =| Pxs) (0 =| Pxs) xp (0 =| Px) 28 | else MkPlayerState xs (ys <+> gravity |*| dt) 29 | (xp <+> xs |*| dt) newYPos 30 | -------------------------------------------------------------------------------- /images/new-cuyama.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timjb/quantities/140357c3ec06e5b29b5d369cb59f1f5925f000a5/images/new-cuyama.jpg -------------------------------------------------------------------------------- /quantities.ipkg: -------------------------------------------------------------------------------- 1 | package quantities 2 | 3 | modules = Quantities, 4 | Quantities.Core, 5 | Quantities.FreeAbelianGroup, 6 | Quantities.ImperialUnits, 7 | Quantities.Information, 8 | Quantities.NonSIUnits, 9 | Quantities.Power, 10 | Quantities.Screen, 11 | Quantities.SIBaseQuantities, 12 | Quantities.SIBaseUnits, 13 | Quantities.SIDerivedQuantities, 14 | Quantities.SIDerivedUnits, 15 | Quantities.SIPrefixes 16 | -------------------------------------------------------------------------------- /quantities.nix: -------------------------------------------------------------------------------- 1 | { build-idris-package 2 | , lib 3 | }: 4 | build-idris-package { 5 | name = "quantities"; 6 | version = "2019-01-28"; 7 | 8 | ipkgName = "quantities"; 9 | idrisDeps = [ ]; 10 | 11 | src = ./.; 12 | 13 | meta = { 14 | description = "Idris lib for type-safe computing with physical units"; 15 | homepage = https://github.com/timjb/quantities; 16 | license = lib.licenses.mit; 17 | }; 18 | } -------------------------------------------------------------------------------- /scripts/build-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | rm -rf quantities_doc 4 | idris --mkdoc quantities.ipkg 5 | git checkout gh-pages 6 | git rm -r docs 7 | mv quantities_doc docs 8 | git add docs 9 | git commit -m "updated documentation" 10 | git checkout master 11 | -------------------------------------------------------------------------------- /scripts/publish-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | git push origin gh-pages:gh-pages --------------------------------------------------------------------------------