{"id":17214323,"url":"https://github.com/metaxal/measures","last_synced_at":"2026-01-28T19:36:14.717Z","repository":{"id":11428252,"uuid":"13881215","full_name":"Metaxal/measures","owner":"Metaxal","description":"Units and measurements in Racket","archived":false,"fork":false,"pushed_at":"2018-01-20T19:27:32.000Z","size":71,"stargazers_count":10,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-24T07:11:50.753Z","etag":null,"topics":["racket","si-units"],"latest_commit_sha":null,"homepage":null,"language":"Racket","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Metaxal.png","metadata":{"files":{"readme":"README.md","changelog":null,"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-10-26T09:55:40.000Z","updated_at":"2023-11-28T17:46:42.000Z","dependencies_parsed_at":"2022-08-31T05:40:46.915Z","dependency_job_id":null,"html_url":"https://github.com/Metaxal/measures","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/Metaxal%2Fmeasures","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metaxal%2Fmeasures/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metaxal%2Fmeasures/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Metaxal%2Fmeasures/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Metaxal","download_url":"https://codeload.github.com/Metaxal/measures/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245467226,"owners_count":20620210,"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":["racket","si-units"],"created_at":"2024-10-15T03:02:37.832Z","updated_at":"2026-01-28T19:36:14.666Z","avatar_url":"https://github.com/Metaxal.png","language":"Racket","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Units and Measurements\n\nUnits and measurements in Racket, with conversion facilities between\nunits.\n\nFirst some **warnings**:\n\n* This collection has not been extensively tested. Use with caution and\n  please [report any error that you\n  find](https://github.com/Metaxal/measures/issues).\n\n* Be cautious with non-linear converters \\(e.g., °F to K\\), as\n  converting a temperature difference is not the same as converting a\n  temperature.\n\n* Some bindings from `racket` may be redefined, like `second`, `min` and\n  `drop`. You can use `rename-in` to change these name on `require`.\n\n## 1. Quick example\n\nSay you are traveling at 50 miles per hour:\n\n```racket\n\u003e (define my-speed (m* 50.0 mile (m/ hour)))\n\u003e (measure-\u003evalue my-speed)                 \n'(22.352 m (s -1))                          \n```\n\nHow many kilometers/hour is that?\n\n```racket\n\u003e (measure-\u003evalue (convert my-speed '(km (h -1))))\n'(80.46719999999999 km (h -1))                    \n```\n\nHow many kilometers do you travel during 5 minutes?\n\n```racket\n\u003e (measure-\u003evalue (convert (m* my-speed 5 min) 'km))\n'(6.7056000000000004 km)                            \n```\n\nYou are quite late and have only 13 minutes left before your meeting,\nand you are 21 miles away. How fast would you need to go to be there in\ntime?\n\n```racket\n\u003e (measure-\u003evalue (convert (m/ (m* 21.0 mi) (m* 13 min)) '(mi (h -1))))\n'(96.9230769230769 mi (h -1))                                          \n```\n\n## 2. Basic definitions\n\nA `unit` is a symbol and an exponent. A `measure` is a number and a set\nof units.\n\nBasic arithmetic operations \\(`m+` `m-` `m*` `m/` `m^`\\) are defined to\nwork with measures.\n\nTo ease human interaction, measures can be written in an simple Domain\nSpecific Language \\(DSL\\). A DSL measure can then be:\n\n* a \\(struct\\) measure,\n\n* a number,\n\n* a DSL unit,\n\n* a list with a number followed by one or more DSL units.\n\nA DSL unit can be:\n\n* a \\(struct\\) unit,\n\n* a symbol alone \\(taking the exponent 1 by default\\),\n\n* a list with a symbol and an exponent.\n\nYou can use the multiplication operator `m*` to easily build measures.\n\n```racket\n\u003e (m* 3)                                  \n(measure 3 (set))                         \n\u003e (m* 3 's)                               \n(measure 3 (set (unit 's 1)))             \n\u003e (m* 3 's '(m -1))                       \n(measure 3 (set (unit 'm -1) (unit 's 1)))\n```\n\nThe arithmetic operators automatically convert DSL measures into\n`measures`:\n\n```racket\n\u003e (m+ 2 3)                      \n(measure 5 (set))               \n\u003e (m/ 3 '(2 s))                 \n(measure 3/2 (set (unit 's -1)))\n```\n\nMeasures can be turned back to human readable values with\n`measure-\u003evalue`:\n\n```racket\n\u003e (measure-\u003evalue (m* '(3 s) 5 '(10 m)))  \n'(150 m s)                                \n\u003e (measure-\u003evalue (m* '(3 s) '(5 (s -1))))\n15                                        \n```\n\nAdding or subtracting measures with different units raises an\n`exn:fail:unit` exception:\n\n```racket\n\u003e (measure-\u003evalue (m+ '(3 m (h -1)) '(2 m h)))        \nError: Measures must have the same units.             \nGot: #\u003cset: #(struct:unit m 1) #(struct:unit h 1)\u003e and\n#\u003cset: #(struct:unit h -1) #(struct:unit m 1)\u003e        \n\u003e (measure-\u003evalue (m+ '(3 m (h -1)) '(2 m (h -1))))   \n'(5 m (h -1))                                         \n```\n\n## 3. Units and conversions\n\nAll units have a short and a long name. The short name is the standard\nsymbol, and the long name is more descriptive:\n\n```racket\n\u003e mmHg                                                            \n(measure 166653/1250 (set (unit 'm -1) (unit 's -2) (unit 'kg 1)))\n\u003e millimetre-of-mercury                                           \n(measure 166653/1250 (set (unit 'm -1) (unit 's -2) (unit 'kg 1)))\n```\n\nBy default, all units are converted to SI units. This allows to perform\ndimension reductions when possible.\n\nFor example:\n\n```racket\n\u003e N                                                     \n(measure 1 (set (unit 'm 1) (unit 's -2) (unit 'kg 1))) \n\u003e Pa                                                    \n(measure 1 (set (unit 'm -1) (unit 's -2) (unit 'kg 1)))\n\u003e (m/ (m* 3 N) (m* 2 Pa))                               \n(measure 3/2 (set (unit 'm 2)))                         \n\u003e (m* 3 mi)                                             \n(measure 603504/125 (set (unit 'm 1)))                  \n\u003e (m+ (m* 3 mi) (m* 2 m))                               \n(measure 603754/125 (set (unit 'm 1)))                  \n```\n\nBut it is possible to avoid the implicit conversion to SI units by\nquoting the short name:\n\n```racket\n\u003e (m* 3 'mi)                  \n(measure 3 (set (unit 'mi 1)))\n```\n\n\\(Note that quoting is nicely the same as \"prevent reduction\" to base\nunits.\\) Quoted units can be useful in particular in text files from\nwhich to read measures. They can of course be used together:\n\n```racket\n\u003e (m+ '(5 mi) (m* 2 '(3 mi)))  \n(measure 11 (set (unit 'mi 1)))\n```\n\nSI units are actually quoted units:\n\n```racket\n\u003e (equal? (m* 3 m (m/ 1 s s))\n          (m* '(3 m (s -2))))\n#t                           \n```\n\nHowever, now it is not possible to add quantities of different units,\neven if they have the same dimension:\n\n```racket\n\u003e (m+ (m* 3 'mi) (m* 2 'm))                                \nError: Measures must have the same units.                  \nGot: #\u003cset: #(struct:unit m 1)\u003e and #\u003cset: #(struct:unit mi\n1)\u003e                                                        \n```\n\nKnown quoted  units can still be converted back to SI units:\n\n```racket\n\u003e (convert (m* 3 'mi))                \n(measure 603504/125 (set (unit 'm 1)))\n```\n\nUsing the `convert` function it is also possible to request a conversion\nfrom SI units to non-SI units \\(or, more precisely, non-SI-base units\\):\n\n```racket\n\u003e (convert (m* 3 m)                                    \n            'mile)                                     \n(measure 125/67056 (set (unit 'mi 1)))                 \n\u003e (convert (m* 3 ft (m/ s))                            \n            '(mi (h -1)))                              \n(measure 45/22 (set (unit 'h -1) (unit 'mi 1)))        \n\u003e (convert (m* 10 hecto Pa) 'mmHg)                     \n(measure 1250000/166653 (set (unit 'mmHg 1)))          \n\u003e (m* 2 Pa 3 m m)                                      \n(measure 6 (set (unit 'm 1) (unit 's -2) (unit 'kg 1)))\n\u003e (convert (m* 2 Pa 3 m m) 'N)                         \n(measure 6 (set (unit 'N 1)))                          \n```\n\nIt can also be used to convert to unit prefixes:\n\n```racket\n\u003e (measure-\u003evalue (convert (m* 3 kilo Pa) '(hecto Pa)))\n'(30 Pa h.)                                            \n```\n\nNotes:\n\n* Prefixes are followed by a dot to avoid name collision with units.\n\n* The order of \"units\" is first by exponent then alphabetical \\(ASCII\\),\n  this is why the `h.` is after `Pa`.\n\nThe `convert` function accepts a measure and either:\n\n* the `'base` symbol \\(default\\), to convert to base \\(SI by default\\)\n  units,\n\n* a DSL unit,\n\n* a list of symbols and DSL units.\n\nIt can then be used to convert quoted units to SI units and back to\nquoted units. For example, this is not what we want \\(although it is\ncorrect\\):\n\n```racket\n\u003e (convert (m* 3 'mi) 'yd)                                     \n(measure 1250/381 (set (unit 'm -1) (unit 'yd 1) (unit 'mi 1)))\n```\n\nThis is what we want:\n\n```racket\n\u003e (convert (m* 3 'mi) '(base yd))\n(measure 5280 (set (unit 'yd 1)))\n```\n\nBut of course, without quoted units, we could have written:\n\n```racket\n\u003e (convert (m* 3 mi) 'yd)        \n(measure 5280 (set (unit 'yd 1)))\n```\n\n## 4. Dimensions and contracts\n\nUnits and measures are organized in dimensions.\n\nFor example:\n\n```racket\n(define-dimension time (s second)\n  ....                           \n  (d    day     86400)           \n  (min  minute  60)              \n  (y    year    (m* 1425/4 day)))\n```\n\nThis defines a `time` dimension, a base unit `s` with a long name\n`second`, and several derived units, where a single number expresses a\nratio with respect to the base unit, and an expression denotes a value\nto be used in place of a ratio.\n\nThis also defines the `time/c` contract that can be used in function\ncontracts:\n\n```racket\n\u003e (define/contract (speed a-distance a-time)      \n    (length/c time/c . -\u003e . velocity/c)           \n    (m/ a-distance a-time))                       \n\u003e (speed (m* 5 mile) (m* 2 hour))                 \n(measure 1397/1250 (set (unit 's -1) (unit 'm 1)))\n\u003e (speed (m* 5 mile) (m* 2 metre))                \nspeed: contract violation                         \n  expected: time/c                                \n  given: (measure 2 (set (unit 'm 1)))            \n  in: the 2nd argument of                         \n      (-\u003e length/c time/c velocity/c)             \n  contract from: (function speed)                 \n  blaming: top-level                              \n   (assuming the contract is correct)             \n  at: eval:37.0                                   \n```\n\n## 5. A ’measures’ language\n\nThe `measures/lang` language can be used as a short-hand to have all of\n`racket` plus all of of `measures` except that the measures arithmetic\noperators \\(`m+`, etc.\\) replace the normal ones \\(`+`, etc.\\).\n\nAs a consequence, one can write:\n\n```racket\n#lang s-exp measures/lang\n                         \n(+ (* 5 mi) (* 5 km))    \n```\n\nThis is also useful to be used in a terminal by invoking:\n\n```racket\nracket -li measures/lang\n```\n\nThis opens an interaction session where `measures/lang` is loaded.\n\n## 6. Chemical elements\n\nThe `measures/chemical-elements` provides the vector `elements` of the\n118 elements with a number of procedures to extract their information:\n`atomic-number` `atomic-symbol` `chemical-element` `group` `period`\n`atomic-weight` `density` `melting-point` `boiling-point`\n`heat-capacity` `electronegativity` `abundance`.\n\nEach procedure accepts either a number \\(the atomic number\\) or a symbol\n\\(either the atomic symbol or the name of the chemical element\\).\n\nExamples:\n\n```racket\n\u003e (require measures/chemical-elements)          \n\u003e (atomic-number 'Oxygen)                       \n8                                               \n\u003e (atomic-symbol 'Iron)                         \n'Fe                                             \n\u003e (atomic-symbol 2)                             \n'He                                             \n\u003e (chemical-element 'Na)                        \n'Sodium                                         \n\u003e (atomic-weight 'Carbon)                       \n(measure 1.99447483422e-26 (set (unit 'kg 1)))  \n\u003e (m* 3 cl (density 'Mercury))                  \n(measure 0.40600800000000004 (set (unit 'kg 1)))\n```\n\n## 7. Related resources\n\nSome [useful\nconversions](http://en.wikipedia.org/wiki/Conversion_of_units) can be\nfound on Wikipedia \\(to be trusted with caution of course\\).\n\nThis collection was partly inspired by [the Frink programming\nlanguage](http://futureboy.us/frinkdocs/) and Konrad Hinsen’s [Clojure\nunits library](http://code.google.com/p/clj-units/).\n\nSee also AlexKnauth’s\n[measures-with-dimensions](https://github.com/AlexKnauth/measures-with-dimensions).\n\nYou may also be interested in [Doug Williams scientific\ncollection](http://planet.racket-lang.org/package-source/williams/science.plt/4/2/planet-docs/science/physical-constants.html).\n\n## 8. License and Disclaimer\n\nCopyright \\(c\\) 2013 Laurent Orseau\n\nLicensed under the GNU LGPL. See LICENSE.\n\n`THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS`   \n`“AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT`     \n`LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR` \n`A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT`  \n`HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,`\n`SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT`      \n`LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,` \n`DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY` \n`THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT`   \n`(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE` \n`OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.`  \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaxal%2Fmeasures","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmetaxal%2Fmeasures","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmetaxal%2Fmeasures/lists"}