aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/type/unit.lux
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/source/lux/type/unit.lux')
-rw-r--r--stdlib/source/lux/type/unit.lux183
1 files changed, 183 insertions, 0 deletions
diff --git a/stdlib/source/lux/type/unit.lux b/stdlib/source/lux/type/unit.lux
new file mode 100644
index 000000000..de00fb82d
--- /dev/null
+++ b/stdlib/source/lux/type/unit.lux
@@ -0,0 +1,183 @@
+(;module:
+ lux
+ (lux (control [monad #+ do Monad]
+ ["p" parser "p/" Monad<Parser>]
+ [eq #+ Eq]
+ [order #+ Order]
+ [enum #+ Enum])
+ (data text/format
+ (number ["r" ratio]))
+ [meta]
+ (meta [code]
+ ["s" syntax #+ syntax:]
+ (syntax ["cs" common]
+ (common ["csr" reader]
+ ["csw" writer])))))
+
+(type: #export (Qty unit)
+ [Int unit])
+
+(sig: #export (Scale s)
+ (: (All [u] (-> (Qty u) (Qty (s u))))
+ scale)
+ (: (All [u] (-> (Qty (s u)) (Qty u)))
+ de-scale)
+ (: r;Ratio
+ ratio))
+
+(type: #export Pure
+ (Qty []))
+
+(type: #export (Per d n)
+ (-> d n))
+
+(type: #export (Inverse u)
+ (|> Pure (Per u)))
+
+(type: #export (Product p s)
+ (|> s (Per (Inverse p))))
+
+(def: #export (in carrier magnitude)
+ (All [unit] (-> unit Int (Qty unit)))
+ [magnitude carrier])
+
+(def: #export (pure magnitude)
+ (-> Int Pure)
+ (in [] magnitude))
+
+(def: #export (out quantity)
+ (All [unit] (-> (Qty unit) Int))
+ (let [[magnitude carrier] quantity]
+ magnitude))
+
+(def: (carrier quantity)
+ (All [unit] (-> (Qty unit) unit))
+ (let [[magnitude carrier] quantity]
+ carrier))
+
+(do-template [<name> <tag>]
+ [(def: <name>
+ (-> Text Text)
+ (|>. (format "{" kind "@" module "}")
+ (let [[module kind] (ident-for <tag>)])))]
+
+ [unit-name #;;Unit]
+ [scale-name #;;Scale]
+ )
+
+(syntax: #export (unit: [export csr;export]
+ [name s;local-symbol]
+ [annotations (p;default cs;empty-annotations csr;annotations)])
+ (wrap (list (` (type: (~@ (csw;export export)) (~ (code;local-symbol name))
+ (~ (csw;annotations annotations))
+ (primitive (~ (code;local-symbol (unit-name name))))))
+ (` (def: (~@ (csw;export export)) (~ (code;local-symbol (format "@" name)))
+ (~ (code;local-symbol name))
+ (:!! [])))
+ )))
+
+(def: ratio^
+ (s;Syntax r;Ratio)
+ (s;tuple (do p;Monad<Parser>
+ [numerator s;int
+ _ (p;assert (format "Numerator must be positive: " (%i numerator))
+ (i.> 0 numerator))
+ denominator s;int
+ _ (p;assert (format "Denominator must be positive: " (%i denominator))
+ (i.> 0 denominator))]
+ (wrap [(int-to-nat numerator) (int-to-nat denominator)]))))
+
+(syntax: #export (scale: [export csr;export]
+ [name s;local-symbol]
+ [(^slots [#r;numerator #r;denominator]) ratio^]
+ [annotations (p;default cs;empty-annotations csr;annotations)])
+ (let [g!scale (code;local-symbol name)]
+ (wrap (list (` (type: (~@ (csw;export export)) ((~ g!scale) (~' u))
+ (~ (csw;annotations annotations))
+ (primitive (~ (code;local-symbol (scale-name name))) [(~' u)])))
+ (` (struct: (~@ (csw;export export)) (~ (code;local-symbol (format "@" name)))
+ (;;Scale (~ g!scale))
+ (def: (~' scale)
+ (|>. ;;out
+ (i.* (~ (code;int (nat-to-int numerator))))
+ (i./ (~ (code;int (nat-to-int denominator))))
+ (;;in (:! ((~ g!scale) ($ +0)) []))))
+ (def: (~' de-scale)
+ (|>. ;;out
+ (i.* (~ (code;int (nat-to-int denominator))))
+ (i./ (~ (code;int (nat-to-int numerator))))
+ (;;in (:! ($ +0) []))))
+ (def: (~' ratio)
+ [(~ (code;nat numerator)) (~ (code;nat denominator))])))
+ ))))
+
+(do-template [<name> <op>]
+ [(def: #export (<name> param subject)
+ (All [unit] (-> (Qty unit) (Qty unit) (Qty unit)))
+ (|> (out subject) (<op> (out param)) (in (carrier subject))))]
+
+ [++ i.+]
+ [-- i.-]
+ )
+
+(def: #export (// param subject)
+ (All [p s] (-> (Qty p) (Qty s) (|> (Qty s) (Per (Qty p)))))
+ (function [input]
+ (|> (out subject)
+ (i.* (out input))
+ (i./ (out param))
+ (in (carrier subject)))))
+
+(def: #export (** param subject)
+ (All [p s] (-> (Qty p) (Qty s) (Product (Qty p) (Qty s))))
+ (function [input]
+ (|> (out subject)
+ (i.* (out (input param)))
+ (in (carrier subject)))))
+
+(def: #export (re-scale from to quantity)
+ (All [si so u] (-> (Scale si) (Scale so) (Qty (si u)) (Qty (so u))))
+ (let [[numerator denominator] (|> (:: to ratio) (r;q./ (:: from ratio)))]
+ (|> quantity out
+ (i.* (nat-to-int numerator))
+ (i./ (nat-to-int denominator))
+ (in (:! (($ +1) ($ +2)) [])))))
+
+(scale: #export Kilo [1 1_000])
+(scale: #export Mega [1 1_000_000])
+(scale: #export Giga [1 1_000_000_000])
+
+(scale: #export Milli [ 1_000 1])
+(scale: #export Micro [ 1_000_000 1])
+(scale: #export Nano [1_000_000_000 1])
+
+(def: #export (as scale unit magnitude)
+ (All [s u] (-> (Scale s) u Int (Qty (s u))))
+ (let [[_ carrier] (|> 0 (in unit) (:: scale scale))]
+ [magnitude carrier]))
+
+(unit: #export Gram)
+(unit: #export Meter)
+(unit: #export Litre)
+(unit: #export Second)
+
+(struct: #export Eq<Unit> (All [unit] (Eq (Qty unit)))
+ (def: (= reference sample)
+ (i.= (out reference) (out sample))))
+
+(struct: #export Order<Unit> (All [unit] (Order (Qty unit)))
+ (def: eq Eq<Unit>)
+
+ (do-template [<name> <func>]
+ [(def: (<name> reference sample)
+ (<func> (out reference) (out sample)))]
+
+ [< i.<]
+ [<= i.<=]
+ [> i.>]
+ [>= i.>=]))
+
+(struct: #export Enum<Unit> (All [unit] (Enum (Qty unit)))
+ (def: order Order<Unit>)
+ (def: (succ qty) (|> (out qty) i.inc (in (carrier qty))))
+ (def: (pred qty) (|> (out qty) i.dec (in (carrier qty)))))