-
-
Save eduardoejp/47cf26c1aded95303238c1ec1bacc1ef to your computer and use it in GitHub Desktop.
Toy example of an extension for the Lux analysis phase for doing type-agnostic arithmetic (specifically, addition)
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
... Arithmetical operations are defined on a per-type basis. | |
... Here, we'll define a "universal" way of adding numbers that works on the default numerical types in Lux, so long as the types of all the parameters line up. | |
(.require | |
[library | |
[lux (.except) | |
[abstract | |
["[0]" monad (.only do)]] | |
[control | |
[try (.only Try)] | |
["<>" parser] | |
["[0]" exception (.only Exception)]] | |
[data | |
[text | |
["%" \\format]] | |
[collection | |
["[0]" list (.use "[1]#[0]" mix)]]] | |
[meta | |
[extension (.only analysis)] | |
["[0]" code | |
["<[1]>" \\parser]] | |
[macro | |
[syntax (.only syntax)]] | |
[type | |
["[0]" check]] | |
[compiler | |
["[0]" phase (.use "[1]#[0]" monad)] | |
[language | |
[lux | |
["[0]" analysis (.only Analysis Operation Phase) | |
["[0]" type]]]] | |
[meta | |
[archive (.only Archive)]]]]]] | |
[/ | |
[number | |
["[0]" nat] | |
["[0]" int] | |
["[0]" rev] | |
["[0]" frac]]]) | |
(exception.def (no_arithmetic_for type) | |
(Exception Type) | |
(exception.report | |
(list ["Type" (%.type type)]))) | |
(def (composite phase archive <+> last prevs) | |
(-> Phase Archive Code Analysis (List Analysis) (Operation Analysis)) | |
(when <+> | |
[_ {.#Text $}] | |
(phase#in (list#mix (function (_ left right) | |
{analysis.#Extension $ (list left right)}) | |
last | |
prevs)) | |
_ | |
(do phase.monad | |
[[_ $] (type.inferring | |
(phase archive <+>))] | |
(in (list#mix (function (_ left right) | |
(analysis.reified [$ (list left right)])) | |
last | |
prevs))))) | |
(with_expansions [<scenarios> (these [.Nat (in (analysis.nat 0)) "lux i64 +"] | |
[.Int (in (analysis.int +0)) "lux i64 +"] | |
[.Rev (in (analysis.rev .0)) "lux i64 +"] | |
[.Frac (in (analysis.frac +0.0)) "lux f64 +"])] | |
(analysis ("universal +" self phase archive [operands (<>.some <code>.any)]) | |
(<| type.with_var | |
(function (_ [$it :it:])) | |
(do [! phase.monad] | |
[operands (monad.each ! (|>> (phase archive) (type.expecting :it:)) | |
operands) | |
_ (type.inference :it:) | |
:it: (type.check (check.identity (list) $it))] | |
(when (list.reversed operands) | |
(list single) | |
(in single) | |
(list) | |
(`` (cond (check.subsumes? .I64 :it:) | |
(phase.except ..no_arithmetic_for [:it:]) | |
(,, (with_template [<type> <0> <+>] | |
[(check.subsumes? <type> :it:) | |
<0>] | |
<scenarios>)) | |
... else | |
(phase.except ..no_arithmetic_for [:it:]))) | |
(list.partial last prevs) | |
(`` (cond (check.subsumes? .I64 :it:) | |
(phase.except ..no_arithmetic_for [:it:]) | |
(,, (with_template [<type> <0> <+>] | |
[(check.subsumes? <type> :it:) | |
(..composite phase archive (` <+>) last prevs)] | |
<scenarios>)) | |
... else | |
(phase.except ..no_arithmetic_for [:it:])))))))) | |
(def .public + | |
(syntax (_ [operands (<>.some <code>.any)]) | |
(in (list (` ("universal +" (,* operands))))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment