{"id":13831937,"url":"https://github.com/timjb/quantities","last_synced_at":"2026-02-09T06:32:09.069Z","repository":{"id":12510139,"uuid":"15179826","full_name":"timjb/quantities","owner":"timjb","description":"Type-safe physical computations and unit conversions in Idris ⚖ 🌡 ⏲ 🔋 📐","archived":false,"fork":false,"pushed_at":"2019-01-28T15:20:43.000Z","size":290,"stargazers_count":159,"open_issues_count":1,"forks_count":11,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-02-04T20:32:16.611Z","etag":null,"topics":["type-safety","unit-conversion","units-of-measure"],"latest_commit_sha":null,"homepage":"http://timbaumann.info/quantities/docs","language":"Idris","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timjb.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-12-14T04:12:34.000Z","updated_at":"2024-12-27T16:24:26.000Z","dependencies_parsed_at":"2022-08-31T12:51:19.618Z","dependency_job_id":null,"html_url":"https://github.com/timjb/quantities","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timjb%2Fquantities","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timjb%2Fquantities/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timjb%2Fquantities/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timjb%2Fquantities/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timjb","download_url":"https://codeload.github.com/timjb/quantities/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246237429,"owners_count":20745348,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["type-safety","unit-conversion","units-of-measure"],"created_at":"2024-08-04T10:01:44.853Z","updated_at":"2026-02-09T06:32:04.048Z","avatar_url":"https://github.com/timjb.png","language":"Idris","funding_links":[],"categories":["Idris"],"sub_categories":[],"readme":"# Quantities [![Build Status](https://travis-ci.org/timjb/quantities.svg?branch=master)](https://travis-ci.org/timjb/quantities)\n\nQuantities is a library for type-safe physical computations and unit conversions in Idris.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"images/new-cuyama.jpg\" alt=\"New Cuyama\" /\u003e\n\u003c/p\u003e\n\n([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/) \u0026ndash; sign first seen on Andrew Kennedy's [Units-of-Measure page](http://research.microsoft.com/en-us/um/people/akenn/units/))\n\nI'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!\n\n## Installation\n\nCopy this package and run\n\n```bash\n$ idris --install quantities.ipkg\n```\nTo use it in your program, run Idris with\n\n```bash\n$ idris -p quantities yourprogram.idr\n```\n\n**Compatibility: Tested with Idris 1.3.1**\n\n## Documentation\n\n### Quantities\n\nQuantities 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:\n\n```idris\nArea : Quantity\nArea = Length \u003c*\u003e Length\n\nSpeed : Quantity\nSpeed = Length \u003c/\u003e Time\n\nVolume : Quantity\nVolume = Length ^ 3\n\nFrequency : Quantity\nFrequency = Time ^ (-1)\n```\n\nAbove we defined the quantities `Area`, `Speed`, `Volume` and `Frequency` in terms of `Length` and `Time`. By convention, we write quantities with capital letters.\n\n\n### Dimensions\n\nOf 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:\n\n```idris\nLength : Dimension\nLength = MkDimension \"Length\"\n\nTime : Dimension\nTime = MkDimension \"Time\"\n\nHappiness : Dimension\nHappiness = MkDimension \"Happiness\"\n```\n\nThe `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 -\u003e Quantity`, which implicitly converts dimensions to quantities.\n\n\n### Units\n\nA unit represents a specific amount of a quantity. For example, we have\n\n```idris\nCentimetre : Unit Length\nSecond : Unit Time\nAmpere : Unit ElectricCurrent\nNewton : Unit Force\n```\n\nNotice 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 \u003c*\u003e Length`. Therefore, we have the functions\n\n```idris\n(\u003c**\u003e) : {q : Quantity} -\u003e {r : Quantity} -\u003e Unit q -\u003e Unit r -\u003e Unit (q \u003c*\u003e r)\n(\u003c//\u003e) : {q : Quantity} -\u003e {r : Quantity} -\u003e Unit q -\u003e Unit r -\u003e Unit (q \u003c/\u003e r)\n(^^)   : {q : Quantity} -\u003e Unit r -\u003e (i : Integer) -\u003e Unit (q ^ i)\n```\n\nFor example:\n\n```idris\nSquareCentimetre : Unit Area\nSquareCentimetre = Centimetre \u003c**\u003e Centimetre -- = Centimetre ^^ 2\n\nMetrePerSecond : Unit Speed\nMetrePerSecond = Meter \u003c//\u003e Second\n\nCubicCentimetre : Unit Volume\nCubicCentimetre = Centimetre ^^ 3\n\nNewton : Unit ((Length \u003c*\u003e Mass) \u003c/\u003e (Time ^ 2))\nNewton = (Metre \u003c**\u003e Kilogram) \u003c//\u003e (Second ^^ 2)\n```\n\n\n### Elementary Units\n\nWe have to start somewhere by defining some base units:\n\n```idris\nMetre : ElemUnit Length\nMetre = MkElemUnit \"m\" 1\n\nSecond : ElemUnit Time\nSecond = MkElemUnit \"s\" 1\n\nCandela : ElemUnit LuminousIntensity\nCandela = MkElemUnit \"cd\" 1\n\n-- 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\nPuppy : ElemUnit Happiness\nPuppy = MkElemUnit \"puppy\" 1\n```\n\nThese 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.\n\nElementary 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:\n\n```idris\nMile : ElemUnit Length\nMile = \u003c one \"mile\" equals 1609.344 Metre \u003e\n\n-- Speed of light\nC_0 : ElemUnit Speed\nC_0 = \u003c one \"c_0\" equals 299792458 (Metre \u003c//\u003e Second) \u003e\n\n-- If you're like me ...\nKitten : ElemUnit Happiness\nKitten = \u003c one \"kitten\" equals 1.5 Puppy \u003e\n```\n\nUnits 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.\n\nElementary units are implicitly converted to units by the function\n\n```idris\nelemUnitToUnit : {q : Quantity} -\u003e ElemUnit q -\u003e Unit q\n```\n\n\n### Measurements\n\nMeasurements are values tagged with a unit.\n\n```idris\ndata Measurement : {q : Quantity} -\u003e Unit q -\u003e Type -\u003e Type where\n  (=|) : a -\u003e (u : Unit q) -\u003e Measurement u a\n```\n\nSince `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:\n\n```idris\nF : Unit q -\u003e Type\nF u = Measurement u Float\n```\n\nFor example:\n\n```idris\ndistanceToMoon : F Metre\ndistanceToMoon = 384400000.0 =| Metre\n```\n\n\n### Converting between units\n\nSometimes, a conversion isn't necessary. For example, the unit `Newton` is definitionally equal to `(Metre \u003c**\u003e Kilogram) \u003c//\u003e (Second ^^ 2)`, so you won't have to convert between these. But generally, you will need a conversion function.\n\n```idris\ndistanceToMoonInMiles : F miles\ndistanceToMoonInMiles = convertTo Mile distanceToMoon\n\n-- According to Wikipedia\nDogYear : ElemUnit Time\nDogYear = \u003c one \"dy\" equals 52 Day \u003e\n\nmyAgeInDogYears : F DogYear\nmyAgeInDogYears = (21 =| Year) `as` DogYear\n```\n\nSince 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\n\n```idris\nconvertTo : {from : Unit q} -\u003e (to : Unit q) -\u003e F from -\u003e F to\nconvert   : {from : Unit q} -\u003e {to : Unit q} -\u003e F from -\u003e F to\nas        : {from : Unit q} -\u003e F from -\u003e (to : Unit q) -\u003e F to\n```\n\n\n### Calculations with measurements\n\nLet'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?\n\n```idris\nweight : F Kilogram\nweight = 2 =| Kilogram\n\nheight : F Metre\nheight = 2 =| Metre\n\nduration : F Second\nduration = 0.8 =| Second\n\ng_0 : F (Metre \u003c//\u003e (Second ^^ 2))\ng_0 = 9.80665 =| (Metre \u003c//\u003e (Second ^^ 2))\n\naveragePower : F Watt\naveragePower = convert $ (weight |*| height |*| g_0) |/| duration\n-- = 49.033 Watt\n```\n\nThis example shows how to multiply measurements using the functions\n\n```idris\n(|*|) : Num a =\u003e {u : Unit q} -\u003e {v : Unit r} -\u003e u :| a -\u003e v :| a -\u003e (u \u003c**\u003e v) :| a\n(|/|) : {u : Unit q} -\u003e {v : Unit r} -\u003e F u -\u003e F v -\u003e F (u \u003c//\u003e v)\n(|^|) : {u : Unit q} -\u003e F u -\u003e (i : Integer) -\u003e F (u ^^ i)\n```\n\nWe can even use these functions to multiply measurements with scalar values:\n\n```idris\nenergyConversionEfficiency : F One\nenergyConversionEfficiency = 0.88 =| One\n\nbatteryCapacity : F (Watt \u003c**\u003e Hour)\nbatteryCapacity = 85000 =| (Watt \u003c**\u003e Hour)\n\nusedEnergy : F (Watt \u003c**\u003e Hour)\nusedEnergy = convert $ energyConversionEfficiency |*| batteryCapacity\n```\n\nWe can add and subtract measurements, too, but only if they have the same unit:\n\n```idris\n(\u003c+\u003e) : Num a =\u003e Measurement u a -\u003e Measurement u a -\u003e Measurement u a\n(\u003c-\u003e) : Num a =\u003e Measurement u a -\u003e Measurement u a -\u003e Measurement u a\n```\n\nFor example:\n\n```idris\neatChocolateCake : F Puppy -\u003e F Puppy\neatChocolateCake x = x \u003c+\u003e (2 =| Puppy)\n```\n\n\n### Predefined quantities and units\n\nThe library comes with many quantities and units predefined.\n\nFrom the [International System of Units (SI)](http://en.wikipedia.org/wiki/International_System_of_Units):\n\n* [`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`\n* [`Quantities.SIDerivedQuantities`](https://github.com/timjb/quantities/blob/master/Quantities/SIDerivedQuantities.idr): SI derived quantites, e.g. `Velocity`, `Acceleration`, `ElectricResistance`, `Energy`, etc.\n* [`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`\n* [`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`\n\nThese four modules are reexported by the main module [`Quantities`](https://github.com/timjb/quantities/blob/master/Quantities.idr).\n\nOther quantities and units:\n\n* [`Quantities.ImperialUnits`](https://github.com/timjb/quantities/blob/master/Quantities/ImperialUnits.idr): Imperial units, e.g. `Mile`, `Inch`, `Gallon`, `Pound`\n* [`Quantities.NonSIUnits`](https://github.com/timjb/quantities/blob/master/Quantities/NonSIUnits.idr): Various common and uncommon units, e.g. `Minute`, `Electronvolt`, `Calorie`, `Tonne`, `LightYear`\n* [`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.\n* [`Quantities.Screen`](https://github.com/timjb/quantities/blob/master/Quantities/Screen.idr): The quantity `ScreenLength` with the unit `Pixel`. Useful for UI programming.\n\n\n### Metric Prefixes\n\nAll standard [SI prefixes](http://en.wikipedia.org/wiki/Metric_prefix) are supported. For example:\n\n```idris\nimport Quantities\n\nmicroscopeResolution : F (nano Metre)\nmicroscopeResolution = 180 =| (nano Metre)\n\nperformance : F (mega Watt)\nperformance = 3.1 =| (mega Watt)\n```\n\n\n## Example\n\nA simple example that demonstrates how one could use quantities to implement simple movement with gravity in a game.\n\n```idris\nmodule Game\n\nimport Quantities\nimport Quantities.Screen\n\nScreenSpeed : Quantity\nScreenSpeed = ScreenLength \u003c/\u003e Time\n\nPxs : Unit ScreenSpeed\nPxs = Pixel \u003c//\u003e Second\n\nrecord PlayerState where\n  constructor MkPlayerState\n  xSpeed : F Pxs\n  ySpeed : F Pxs\n  xPos   : F Px\n  yPos   : F Px\n\ngravity : Quantities.Core.F (Pxs \u003c//\u003e Second)\ngravity = -800 =| (Pxs \u003c//\u003e Second)\n\n-- Update player position and speed after a given duration\nupdatePlayerState : F Second -\u003e PlayerState -\u003e PlayerState\nupdatePlayerState dt (MkPlayerState xs ys xp yp) =\n  let newYPos = yp \u003c+\u003e ys |*| dt\n  in if newYPos \u003c= (0 =| Px)\n       then MkPlayerState (0 =| Pxs) (0 =| Pxs) xp (0 =| Px)\n       else MkPlayerState xs (ys \u003c+\u003e gravity |*| dt)\n                          (xp \u003c+\u003e xs |*| dt) newYPos\n```\n\n## Contributing\n\nFeedback and pull requests adding code and units are welcome!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimjb%2Fquantities","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimjb%2Fquantities","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimjb%2Fquantities/lists"}