-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Part way through writing a meta-library for units that cost nothing at runtime but give unit-type safety at compile time.
- Loading branch information
1 parent
352a946
commit ad253db
Showing
8 changed files
with
309 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
[ n seive-of-sundaram-into: primes | uint, &list of: uint -> ø | | ||
limit = (n - 1) / 2 | ||
|
||
marked: (array of: bool length: limit + 1) | ||
marked fill-with: false | ||
|
||
1 to: limit do: [ i | | ||
j = i | ||
[(i + j + 2 * i * j) ≤ limit] while-true: [ | ||
marked[i + j + 2 * i * j] = true | ||
j += 1] | ||
|
||
n ≥ 2 then: [list add: 2] | ||
1 to: limit do: [ i | | ||
marked[i] then: [list add: 2 * i + 1] ] ] |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Units and Quantities | ||
|
||
It is smarter to program with units than without. What is a 10 after all when it should be 10 bytes? | ||
We can create an array as either (array of: u8 length: 10) but how do we describe what we would create? | ||
with a quantity: {quantity of: u8 | magnitude: 10} | ||
|
||
SI units and their derived units exist as pre-made quantity classes which lets you write: | ||
100 seconds // returns a {quantity of: second | magniature: 100} | ||
|
||
You can describe the processing rate of your data with your own classes combined with SI units. | ||
processing-speed-type = person / second | ||
processing-speed-quantity = quantity of: processing-speed-type | ||
|
||
When adding or substracting two quantities if their base unit doesn't match there is a compile time error. | ||
This can avoid a lot of numerical type bugs. The unit system has no overhead on runtime, only compile time. | ||
|
||
When describing bytes or bits you can define an array type without having to specify a second parameter | ||
for length: | ||
my-buffer = array of: 4 kilobytes | ||
|
||
|
||
Every base and derived unit used is assigned a unique id that is a prime number allowing any combination | ||
of unit to be combined through multiplication and division. meter^2 is meter id * meter id while byte/second | ||
is byte id / second id. These id's are assigned lazily as they are needed in your code at compile time. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#package core | ||
|
||
quantity = ( | ||
#traits: (number-t,) | ||
@of: (unit: unit-t) | ||
magnitude: number-t ) | ||
|
||
|
||
/* number-t */ | ||
[ a + b | ||
| quantity of: a unit, quantity of: a unit -> quantity of: a unit | ||
| {magnitude: a magnitude + b magnitude} ] | ||
|
||
[ a + b | ||
| quantity of: a unit base, quantity of: a unit base -> quantity of: a unit base | ||
| {magnitude: a magnitude + b magnitude * b unit conversion / a unit conversion} ] | ||
|
||
[ a - b | ||
| quantity of: a unit, quantity of: a unit -> quantity of: a unit | ||
| {magnitude: a magnitude - b magnitude} ] | ||
|
||
[ a - b | ||
| quantity of: a unit base, quantity of: a unit base -> quantity of: a unit base | ||
| {magnitude: a magnitude - b magnitude * b unit conversion / a unit conversion} ] | ||
|
||
[ a * b | ||
| quantity, quantity -> quantity of: a unit * b unit | ||
| {magnitude: a magnitude * b magnitude} ] | ||
|
||
[ a * magnitude | ||
| quantity, number-t -> quantity of: a unit | ||
| {magnitude: a magnitude * magnitude} ] | ||
|
||
[ magnitude * a | ||
| number-t, quantity -> quantity of: a unit | ||
| {magnitude: magnitude * a magnitude} ] | ||
|
||
[ a / b | ||
| quantity, quantity -> quantity of: a unit / b unit | ||
| {magnitude: a magnitude / b magnitude} ] | ||
|
||
[ a / magnitude | ||
| quantity, number-t -> quantity of: a unit | ||
| {magnitude: a magnitude / magnitude} ] | ||
|
||
[ magnitude / a | ||
| number-t, quantity -> quantity of: 1 / a unit | ||
| {magnitude: magnitude * a magnitude} ] | ||
|
||
[ a floor | ||
| quantity -> a | ||
| {magnitude: magnitude floor} ] | ||
|
||
[ a ceiling | ||
| quantity -> a | ||
| {magnitude: magnitude ceiling} ] | ||
|
||
[ a round | ||
| quantity -> a | ||
| {magnitude: magnitude round} ] | ||
|
||
[ a truncate | ||
| quantity -> a | ||
| {magnitude: magnitude truncate} ] | ||
|
||
|
||
/* comparable-t */ | ||
[ a < b | ||
| quantity of: a unit base, quantity of: a unit base -> bool | ||
| a magnitude < b magnitude ] | ||
|
||
[ a == b | ||
| quantity of: a unit base, quantity of: a unit base -> bool | ||
| a magnitude == b magnitude ] | ||
|
||
|
||
/* hashable-t */ | ||
[ a hash | quantity | magnitude hash + unit hash ] | ||
|
||
|
||
/* convertable-t */ | ||
[ a as: new-unit | quantity -> quantity | unit convert: magnitude to: new-unit ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
#package core | ||
|
||
unitless = base-unit-t symbol: empty'empty' | ||
primary-unit-library = {&unit-library | new init} | ||
primary-unit-library unit-ids[unitless]: 1 | ||
|
||
meter = base-unit-t symbol: 'm' | ||
second = base-unit-t symbol: 's' | ||
gram = base-unit-t symbol: 'g' // the si unit is kilogram but that makes the init code harder | ||
mole = base-unit-t symbol: 'mol' | ||
kelvin = base-unit-t symbol: 'L' | ||
ampere = base-unit-t symbol: 'A' | ||
candela = base-unit-t symbol: 'cd' | ||
|
||
// useful but not an SI unit | ||
byte = base-unit-t symbol: 'B' | ||
|
||
// controversial apparently | ||
|
||
// si scaled versions of base units | ||
( meter, second, gram, mole, kelvin, ampere, candela, ) do: [ unit | register-derived-si-prefixes: si-negative-prefixes ] | ||
( meter, gram, mole, kelvin, ampere, candela, byte ) do: [ unit | register-derived-si-prefixes: si-positive-prefixes ] | ||
|
||
// si approved derived units | ||
hertz = derived-unit-t base: 1 / second symbol: 'Hz' | ||
newton = derived-unit-t base: kilogram * meter * (second ** -2) symbol: 'N' | ||
pascal = derived-unit-t base: newton * (meter ** -2) symbol: 'Pa' | ||
joule = derived-unit-t base: newton * meter symbol: 'J' | ||
watt = derived-unit-t base: joule / second symbol: 'W' | ||
coulomb = derived-unit-t base: ampere * second symbol: 'C' | ||
volt = derived-unit-t base: watt / ampere symbol: 'V' | ||
farad = derived-unit-t base: coulomb / volt symbol: 'F' | ||
ohm = derived-unit-t base: volt / ampere symbol: 'Ω' | ||
siemens = derived-unit-t base: ampere / volt symbol: 'S' | ||
webere = derived-unit-t base: volt * second symbol: 'Wb' | ||
tesla = derived-unit-t base: weber * (meter ** -2) symbol: 'T' | ||
henry = derived-unit-t base: weber / ampere symbol: 'H' | ||
celcius = derived-unit-t base: kelvin symbol: 'ºC' offset: -273.15 | ||
radian = base-unit-t symbol: 'rad' | ||
steradian = base-unit-t symbol: 'sr' | ||
lumen = derived-unit-t base: candela * steradian symbol: 'lm' | ||
lux = derived-unit-t base: lumen * (meter ** -2) symbol: 'lx' | ||
becquerel = derived-unit-t base: 1 / second symbol: 'Bq' | ||
gray = derived-unit-t base: joule / kilogram symbol: 'Gy' | ||
katal = derived-unit-t base: mole / second symbol: 'kat' | ||
|
||
( hertz, newton, pascal, joule, watt, coulomb, volt, farad, ohm, siemens, weber, | ||
tesla, henry, celcius, radian, steradian, lumen, lux, becquerl, gray, katal, ) do: [ unit | | ||
register-derived-si-prefixes: si-negative-prefixes | ||
register-derived-si-prefixes: si-positive-prefixes ] | ||
|
||
// derived distance | ||
inch = derived-unit-t base: meter symbol: 'in' scale: 254 / 10_000 | ||
foot = derived-unit-t base: meter symbol: "ft" scale: 3_048 / 10_000 | ||
yard = derived-unit-t base: meter symbol: 'yd' scale: 9_144 / 10_000 | ||
mile = derived-unit-t base: meter symbol: 'mi' scale: 1_609_344 / 1_000 | ||
light-year = derived-unit-t base: meter symbol: 'lightyear' scale: 9_460_500_000_000_000 | ||
parsec = derived-unit-t base: meter symbol: 'parsec' scale: 30_856_770_000_000_000 | ||
|
||
// derived time | ||
minute = derived-unit-t base: second symbol: 'min' scale: 60 | ||
hour = derived-unit-t base: second symbol: 'hr' scale: 60 | ||
day = derived-unit-t base: second symbol: 'd' scale: 24 | ||
week = derived-unit-t base: second symbol: 'wk' scale: 7 | ||
year = derived-unit-t base: second symbol: 'y' scale: 315_569_259_747 / 10_000 | ||
decade = derived-unit-t base: second symbol: 'decade' symbol: 'decade' scale: 315_569_259_747 / 1_000 | ||
century = derived-unit-t base: second symbol: 'century' symbol: 'century' scale: 315_569_259_747 / 100 | ||
millenium = derived-unit-t base: second symbol: 'millenium' symbol: 'millenium' scale: 315_569_259_747 / 10 | ||
|
||
// derived weight | ||
tonne = derived-unit-t base: gram symbol: 't' scale: 1_000_000 | ||
stone = derived-unit-t base: gram symbol: 'st' scale: 6_350_29_318 / 100_000 | ||
pound = derived-unit-t base: gram symbol: 'lb' scale: 453_59_237 / 100_000 | ||
ounce = derived-unit-t base: gram symbol: 'oz' scale: 28_349_523_125 / 1_000_000_000 | ||
carat = derived-unit-t base: gram symbol: 'ct' scale: 2 / 10 | ||
|
||
// derived information | ||
bit = derived-unit-t base: byte symbol: 'b' scale: 1 / 8 | ||
bit register-si-derived-units: si-positive-prefixes scale: 1 / 8 | ||
|
||
// derived angle | ||
degree = derived-unit-t base: radian symbol: 'º' scale: 1_000_000_000_000 / 57_295_779_513_082 | ||
arc-minute = derived-unit-t base: radian symbol: "'" scale: 1000000000000 / 57295779513082 / 60 | ||
arc-second = derived-unit-t base: radian symbol: '"' scale: 1000000000000 / 57295779513082 / 3600 | ||
|
||
// derived areas | ||
meter-squared = meter * meter | ||
acre = derived-unit-t base: meter-squared symbol: 'ac' scale: 40_468_564_224 / 10_000_000 | ||
hectare = derived-unit-t base: meter-squared symbol: 'ha' scale: 10_000 | ||
|
||
// derived powers | ||
horse-power = derived-unit-t base: watt base symbol: 'hp' scale: 7457 / 10 | ||
|
||
// derived pressures | ||
atmosphere = derived-unit-t base: pascal base symbol: 'atm' scale: 101_325 | ||
bar = derived-unit-t base: pascal base symbol: 'bar' scale: 100_000 | ||
psi = derived-unit-t base: pascal base symbol: 'psi' scale: 6_894_757 / 1_000 | ||
|
||
// derived volumes | ||
litre = derived-unit-t base: m ** -3 symbol: 'L' scale: 1 / 1_000 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
#package core | ||
|
||
unit-library = ( | ||
next-id: uint = 2 | ||
ids: ( class, uint | ) ) | ||
|
||
[ library unit-id-for: unit | &!unit-library, class -> fraction | | ||
^ids[unit] else [ | ||
id = next-id | ||
next-id = next-id next-prime | ||
ids[unit]: id ] ] | ||
|
||
#scope private | ||
[ library unit-suffix-for: unit | &unit-library, class -> string | | ||
^unit name ] | ||
|
||
[ library unit-suffix-for: unit | &unit-library, base-unit-t -> string | | ||
^unit class symbol ] | ||
|
||
[ library unit-suffix-for: unit | &unit-library, derived-unit-t -> string | | ||
^unit class symbol ] | ||
|
||
[ library unit-scaling-for: unit | &unit-library, class -> int | | ||
^1 ] | ||
|
||
[ library unit-scaling-for: unit | &unit-library, derived-unit-t -> int | | ||
^unit class scale ] | ||
|
||
[ library unit-base-for: unit | &unit-library, class -> base-unit-t | | ||
^unit ] | ||
|
||
[ library unit-base-for: unit | &unit-library, derived-unit-t -> base-unit-t | | ||
^unit base ] | ||
|
||
|
||
#scope package | ||
|
||
si-unit-prefix = (prefix: string, symbol: string, scale: int) | ||
|
||
positive-prefixes = ( si-unit-prefix | | ||
{prefix: "quetta", symbol: "Q", base: 10 ** 30}, | ||
{prefix: "ronna", symbol: "R", base: 10 ** 27}, | ||
{prefix: "yotta", symbol: "Y", base: 10 ** 24}, | ||
{prefix: "zetta", symbol: "Z", base: 10 ** 21}, | ||
{prefix: "exa", symbol: "E", base: 10 ** 18}, | ||
{prefix: "peta", symbol: "P", base: 10 ** 15}, | ||
{prefix: "tera", symbol: "T", base: 10 ** 12}, | ||
{prefix: "giga", symbol: "G", base: 10 ** 9}, | ||
{prefix: "mega", symbol: "M", base: 10 ** 6}, | ||
{prefix: "kilo", symbol: "K", base: 10 ** 3}, | ||
{prefix: "hecto", symbol: "h", base: 10 ** 2}, | ||
{prefix: "deca", sybmol: "da", base: 10}) | ||
|
||
negative-prefixes = ( si-unit-prefix | | ||
{prefix: "deci", symbol: "d", base: -10}, | ||
{prefix: "centi", symbol: "c", base: 10 ** -2}, | ||
{prefix: "milli", symbol: "m", base: 10 ** -3}, | ||
{prefix: "micro", symbol: "µ", base: 10 ** -6}, | ||
{prefix: "nano", symbol: "n", base: 10 ** -9}, | ||
{prefix: "pico", symbol: "p", base: 10 ** -12}, | ||
{prefix: "femto", symbol: "f", base: 10 ** -15}, | ||
{prefix: "atto", symbol: "a", base: 10 ** -18}, | ||
{prefix: "zepto", symbol: "z", base: 10 ** -21}, | ||
{prefix: "yocto", symbol: "y", base: 10 ** -24}, | ||
{prefix: "ronto", symbol: "r", base: 10 ** -27}, | ||
{prefix: "quecto", symbol: "q", base: 10 ** -30}) | ||
|
||
si-prefixes = positive-prefixes + negative-prefixes | ||
|
||
[ base-unit register-derived-unit: unit-name symbol: unit-symbol | unit-t, string, string, int | | ||
base-unit register-derived-unit: unit-name symbol: unit-symbol scale: 1 ] | ||
|
||
[ base-unit register-derived-unit: unit-name symbol: unit-symbol scale: scale | unit-t, string, string, int | | ||
#context public[unit-name]: (derived-unit base: base-unit symbol: unit-symbol scale: scale) ] ] | ||
|
||
[ base-unit register-derived-si-prefixes: prefixes | base-unit-t, &list of: si-unit-prefix | | ||
base-unit register-derived-si-prefixes: prefixes scale: 1 ] | ||
|
||
[ base-unit register-derived-si-prefixes: prefixes scale: scale | base-unit-t, &list of: si-unit-prefix, int | | ||
base-unit-name = #context public key-for: base-unit | ||
prefixes do: [ prefix | | ||
unit-name = prefix name + base-unit-name | ||
unit-symbol = prefix symbol + base-unit symbol | ||
base-unit register-derived-unit: unit-name symbol: unit-symbol scale: prefix base * int ] ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#package core | ||
|
||
base-unit-t = (@symbol: string,) | ||
derived-unit-t = (@base: base-unit-t, @scale: int, @symbol: string) |