aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--stdlib/source/lux.lux2
-rw-r--r--stdlib/source/lux/data/format/json/codec.lux301
-rw-r--r--stdlib/source/lux/macro/poly.lux571
-rw-r--r--stdlib/source/lux/macro/poly/eq.lux170
-rw-r--r--stdlib/source/lux/macro/poly/functor.lux194
-rw-r--r--stdlib/test/test/lux/macro/poly/eq.lux4
-rw-r--r--stdlib/test/test/lux/macro/poly/functor.lux25
7 files changed, 627 insertions, 640 deletions
diff --git a/stdlib/source/lux.lux b/stdlib/source/lux.lux
index 30f38897b..caf38c7b6 100644
--- a/stdlib/source/lux.lux
+++ b/stdlib/source/lux.lux
@@ -2598,7 +2598,7 @@
(#Cons [_ (#Symbol "" name)] (#Cons body #Nil))
(let' [body' (replace-syntax (list [name (` (#Apply (~ (make-bound +1)) (~ (make-bound +0))))])
(update-bounds body))]
- (return (list (` (#Apply Void (#UnivQ #Nil (~ body')))))))
+ (return (list (` (#Apply #;Void (#UnivQ #Nil (~ body')))))))
_
(fail "Wrong syntax for Rec")))
diff --git a/stdlib/source/lux/data/format/json/codec.lux b/stdlib/source/lux/data/format/json/codec.lux
index 98e3874fd..073d3636b 100644
--- a/stdlib/source/lux/data/format/json/codec.lux
+++ b/stdlib/source/lux/data/format/json/codec.lux
@@ -4,7 +4,7 @@
lux
(lux (control functor
applicative
- ["M" monad #+ do Monad]
+ [monad #+ do Monad]
[eq #+ Eq]
codec
["p" parser "p/" Monad<Parser>])
@@ -191,200 +191,175 @@
(function [input]
(non-rec (rec-encode non-rec) input)))
-(poly: #hidden (Codec<JSON,?>//encode env :x:)
- (let [->Codec//encode (: (-> Code Code)
- (function [.type.] (` (-> (~ .type.) ..;JSON))))]
- (with-expansions
- [<basic> (do-template [<type> <matcher> <encoder>]
- [(do @ [_ (<matcher> :x:)] (wrap (` (: (~ (->Codec//encode (` <type>))) <encoder>))))]
+(poly: #hidden Codec<JSON,?>//encode
+ (with-expansions
+ [<basic> (do-template [<type> <matcher> <encoder>]
+ [(do @
+ [_ <matcher>]
+ (wrap (` (: (~ (@JSON//encode inputT))
+ <encoder>))))]
- [Unit poly;unit (function [(~ (code;symbol ["" "0"]))] #..;Null)]
- [Bool poly;bool ..;boolean]
- [Real poly;real ..;number]
- [Text poly;text ..;string])]
- ($_ macro;either
+ [Unit poly;unit (function [(~ (code;symbol ["" "0"]))] #..;Null)]
+ [Bool poly;bool ..;boolean]
+ [Real poly;real ..;number]
+ [Text poly;text ..;string])]
+ (do @
+ [*env* poly;env
+ #let [@JSON//encode (: (-> Type Code)
+ (function [type]
+ (` (-> (~ (poly;to-ast *env* type)) ..;JSON))))]
+ inputT poly;peek]
+ ($_ p;either
<basic>
- (with-gensyms [g!input g!key g!val]
- (do @
- [[:key: :val:] (poly;apply-2 (ident-for d;Dict) :x:)
- _ (poly;text :key:)
- .val. (Codec<JSON,?>//encode env :val:)]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
- (function [(~ g!input)]
- (|> (~ g!input)
- d;entries
- (;;_map_ (: (-> [Text (~ (poly;to-ast env :val:))]
- [Text ..;JSON])
- (function [[(~ g!key) (~ g!val)]]
- [(~ g!key)
- ((~ .val.) (~ g!val))])))
- (d;from-list text;Hash<Text>)
- #..;Object))
- )))))
(do @
- [:sub: (poly;apply-1 (ident-for ;Maybe) :x:)
- .sub. (Codec<JSON,?>//encode env :sub:)]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
+ [#let [g!key (code;local-symbol "\u0000key")
+ g!val (code;local-symbol "\u0000val")]
+ [_ _ .val.] (poly;apply ($_ p;seq
+ (poly;named (ident-for d;Dict))
+ poly;text
+ Codec<JSON,?>//encode))]
+ (wrap (` (: (~ (@JSON//encode inputT))
+ (|>. d;entries
+ (;;_map_ (function [[(~ g!key) (~ g!val)]]
+ [(~ g!key) ((~ .val.) (~ g!val))]))
+ (d;from-list text;Hash<Text>)
+ #..;Object)))))
+ (do @
+ [[_ .sub.] (poly;apply ($_ p;seq
+ (poly;named (ident-for ;Maybe))
+ Codec<JSON,?>//encode))]
+ (wrap (` (: (~ (@JSON//encode inputT))
(..;nullable (~ .sub.))))))
(do @
- [:sub: (poly;apply-1 (ident-for ;List) :x:)
- .sub. (Codec<JSON,?>//encode env :sub:)]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
+ [[_ .sub.] (poly;apply ($_ p;seq
+ (poly;named (ident-for ;List))
+ Codec<JSON,?>//encode))]
+ (wrap (` (: (~ (@JSON//encode inputT))
(|>. (;;_map_ (~ .sub.)) vector;from-list ..;array)))))
- (with-gensyms [g!input]
- (do @
- [members (poly;sum+ :x:)
- pattern-matching (M;map @
- (function [[tag :case:]]
- (do @
- [g!encode (Codec<JSON,?>//encode env :case:)]
- (wrap (list (` ((~ (code;nat tag)) (~ g!input)))
+ (do @
+ [#let [g!input (code;local-symbol "\u0000input")]
+ members (poly;variant (p;many Codec<JSON,?>//encode))]
+ (wrap (` (: (~ (@JSON//encode inputT))
+ (function [(~ g!input)]
+ (case (~ g!input)
+ (~@ (L/join (L/map (function [[tag g!encode]]
+ (list (` ((~ (code;nat tag)) (~ g!input)))
(` (..;json [(~ (code;real (;;tag tag)))
- ((~ g!encode) (~ g!input))]))))))
- (list;enumerate members))]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
- (function [(~ g!input)]
- (case (~ g!input)
- (~@ (L/join pattern-matching)))))))))
+ ((~ g!encode) (~ g!input))]))))
+ (list;enumerate members))))))))))
(do @
- [members (poly;prod+ :x:)
- #let [g!members (|> (list;size members) n.dec
+ [g!encoders (poly;tuple (p;many Codec<JSON,?>//encode))
+ #let [g!members (|> (list;size g!encoders) n.dec
(list;n.range +0)
- (L/map (|>. nat/encode code;local-symbol)))]
- g!encoders (M;map @ (Codec<JSON,?>//encode env) members)]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
+ (L/map (|>. nat/encode code;local-symbol)))]]
+ (wrap (` (: (~ (@JSON//encode inputT))
(function [[(~@ g!members)]]
(..;json [(~@ (L/map (function [[g!member g!encode]]
(` ((~ g!encode) (~ g!member))))
- (list;zip2 g!members g!encoders)))]))
- ))))
+ (list;zip2 g!members g!encoders)))]))))))
## Type recursion
- (with-gensyms [g!rec]
- (do @
- [:non-rec: (poly;recursive :x:)
- #let [new-env (poly;extend-env [:x: g!rec] (list [:x: (` (;undefined))]) env)]
- .non-rec. (Codec<JSON,?>//encode new-env :non-rec:)]
- (wrap (` (: (~ (poly;gen-type new-env ->Codec//encode g!rec (list) :x:))
- (;;rec-encode (;function [(~ g!rec)]
- (~ .non-rec.))))))))
- (poly;self env :x:)
- (poly;recursion env :x:)
+ (do @
+ [[selfC non-recC] (poly;recursive Codec<JSON,?>//encode)]
+ (wrap (` (: (~ (@JSON//encode inputT))
+ (;;rec-encode (;function [(~ selfC)]
+ (~ non-recC)))))))
+ poly;recursive-self
## Type applications
(do @
- [[:func: :args:] (poly;apply :x:)
- .func. (Codec<JSON,?>//encode env :func:)
- .args. (M;map @ (Codec<JSON,?>//encode env) :args:)]
- (wrap (` (: (~ (->Codec//encode (poly;to-ast env :x:)))
- ((~ .func.) (~@ .args.))))))
- ## Bound type-vars
- (poly;bound env :x:)
+ [partsC (poly;apply (p;many Codec<JSON,?>//encode))]
+ (wrap (` ((~@ partsC)))))
## Polymorphism
- (with-gensyms [g!type-fun]
- (do @
- [[g!vars :non-poly:] (poly;polymorphic :x:)
- #let [new-env (poly;extend-env [:x: g!type-fun]
- (list;zip2 (|> g!vars list;size poly;type-var-indices) g!vars)
- env)]
- .non-poly. (Codec<JSON,?>//encode new-env :non-poly:)]
- (wrap (` (: (All (~ g!type-fun) [(~@ g!vars)]
- (-> (~@ (L/map ->Codec//encode g!vars))
- (~ (->Codec//encode (` ((~ (poly;to-ast env :x:)) (~@ g!vars)))))))
- (function (~ g!type-fun) [(~@ g!vars)]
- (~ .non-poly.)))))))
+ (do @
+ [[funcC varsC bodyC] (poly;polymorphic Codec<JSON,?>//encode)]
+ (wrap (` (: (All [(~@ varsC)]
+ (-> (~@ (L/map (function [varC] (` (-> (~ varC) ..;JSON)))
+ varsC))
+ (-> ((~ (poly;to-ast *env* inputT)) (~@ varsC))
+ ..;JSON)))
+ (function (~ funcC) [(~@ varsC)]
+ (~ bodyC))))))
+ poly;bound
+ poly;recursive-call
## If all else fails...
- (macro;fail ($_ text/append "Cannot create JSON encoder for: " (type;to-text :x:)))
+ (p;fail (text/append "Cannot create JSON encoder for: " (type;to-text inputT)))
))))
-(poly: #hidden (Codec<JSON,?>//decode env :x:)
- (let [->Codec//decode (: (-> Code Code)
- (function [.type.] (` (..;Reader (~ .type.)))))]
- (with-expansions
- [<basic> (do-template [<type> <matcher> <decoder>]
- [(do @ [_ (<matcher> :x:)] (wrap (` (: (~ (->Codec//decode (` <type>))) <decoder>))))]
+(poly: #hidden Codec<JSON,?>//decode
+ (with-expansions
+ [<basic> (do-template [<type> <matcher> <decoder>]
+ [(do @
+ [_ <matcher>]
+ (wrap (` (: (~ (@JSON//decode inputT))
+ <decoder>))))]
- [Unit poly;unit ../reader;null]
- [Bool poly;bool ../reader;boolean]
- [Real poly;real ../reader;number]
- [Text poly;text ../reader;string])]
- ($_ macro;either
+ [Unit poly;unit ../reader;null]
+ [Bool poly;bool ../reader;boolean]
+ [Real poly;real ../reader;number]
+ [Text poly;text ../reader;string])]
+ (do @
+ [*env* poly;env
+ #let [@JSON//decode (: (-> Type Code)
+ (function [type]
+ (` (..;Reader (~ (poly;to-ast *env* type))))))]
+ inputT poly;peek]
+ ($_ p;either
<basic>
(do @
- [[:key: :val:] (poly;apply-2 (ident-for d;Dict) :x:)
- _ (poly;text :key:)
- .val. (Codec<JSON,?>//decode env :val:)]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
- (../reader;object (~ .val.))))))
+ [[_ _ valC] (poly;apply ($_ p;seq
+ (poly;named (ident-for d;Dict))
+ poly;text
+ Codec<JSON,?>//decode))]
+ (wrap (` (: (~ (@JSON//decode inputT))
+ (../reader;object (~ valC))))))
(do @
- [:sub: (poly;apply-1 (ident-for ;Maybe) :x:)
- .sub. (Codec<JSON,?>//decode env :sub:)]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
- (../reader;nullable (~ .sub.))))))
+ [[_ subC] (poly;apply (p;seq (poly;named (ident-for ;Maybe))
+ Codec<JSON,?>//decode))]
+ (wrap (` (: (~ (@JSON//decode inputT))
+ (../reader;nullable (~ subC))))))
(do @
- [:sub: (poly;apply-1 (ident-for ;List) :x:)
- .sub. (Codec<JSON,?>//decode env :sub:)]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
- (../reader;array (p;some (~ .sub.)))))))
+ [[_ subC] (poly;apply (p;seq (poly;named (ident-for ;List))
+ Codec<JSON,?>//decode))]
+ (wrap (` (: (~ (@JSON//decode inputT))
+ (../reader;array (p;some (~ subC)))))))
(do @
- [members (poly;sum+ :x:)
- pattern-matching (M;map @
- (function [[tag :case:]]
- (do @
- [g!decode (Codec<JSON,?>//decode env :case:)]
- (wrap (list (` (|> (~ g!decode)
- (p;after (../reader;number! (~ (code;real (;;tag tag)))))
- ../reader;array))))))
- (list;enumerate members))]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
+ [members (poly;variant (p;many Codec<JSON,?>//decode))]
+ (wrap (` (: (~ (@JSON//decode inputT))
($_ p;alt
- (~@ (L/join pattern-matching)))))))
+ (~@ (L/map (function [[tag memberC]]
+ (` (|> (~ memberC)
+ (p;after (../reader;number! (~ (code;real (;;tag tag)))))
+ ../reader;array)))
+ (list;enumerate members))))))))
(do @
- [members (poly;prod+ :x:)
- #let [g!members (|> (list;size members) n.dec
- (list;n.range +0)
- (L/map (|>. nat/encode code;local-symbol)))]
- g!decoders (M;map @ (Codec<JSON,?>//decode env) members)]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
+ [g!decoders (poly;tuple (p;many Codec<JSON,?>//decode))]
+ (wrap (` (: (~ (@JSON//decode inputT))
(../reader;array ($_ p;seq (~@ g!decoders)))))))
## Type recursion
- (with-gensyms [g!rec]
- (do @
- [:non-rec: (poly;recursive :x:)
- #let [new-env (poly;extend-env [:x: g!rec] (list [:x: (` (;undefined))]) env)]
- .non-rec. (Codec<JSON,?>//decode new-env :non-rec:)]
- (wrap (` (: (~ (poly;gen-type new-env ->Codec//decode g!rec (list) :x:))
- (p;rec (;function [(~ g!rec)]
- (~ .non-rec.))))))))
- (poly;self env :x:)
- (poly;recursion env :x:)
- ## Type applications
(do @
- [[:func: :args:] (poly;apply :x:)
- .func. (Codec<JSON,?>//decode env :func:)
- .args. (M;map @ (Codec<JSON,?>//decode env) :args:)]
- (wrap (` (: (~ (->Codec//decode (poly;to-ast env :x:)))
- ((~ .func.) (~@ .args.))))))
- ## Bound type-vars
+ [[selfC bodyC] (poly;recursive Codec<JSON,?>//decode)]
+ (wrap (` (: (~ (@JSON//decode inputT))
+ (p;rec (;function [(~ selfC)]
+ (~ bodyC)))))))
+ poly;recursive-self
+ ## Type applications
(do @
- [g!bound (poly;bound env :x:)]
- (wrap g!bound))
+ [[funcC argsC] (poly;apply (p;seq Codec<JSON,?>//decode (p;many Codec<JSON,?>//decode)))]
+ (wrap (` ((~ funcC) (~@ argsC)))))
## Polymorphism
- (with-gensyms [g!type-fun]
- (do @
- [[g!vars :non-poly:] (poly;polymorphic :x:)
- #let [new-env (poly;extend-env [:x: g!type-fun]
- (list;zip2 (|> g!vars list;size poly;type-var-indices) g!vars)
- env)]
- .non-poly. (Codec<JSON,?>//decode new-env :non-poly:)]
- (wrap (` (: (All (~ g!type-fun) [(~@ g!vars)]
- (-> (~@ (L/map ->Codec//decode g!vars))
- (~ (->Codec//decode (` ((~ (poly;to-ast env :x:)) (~@ g!vars)))))))
- (function (~ g!type-fun) [(~@ g!vars)]
- (~ .non-poly.)))))))
+ (do @
+ [[funcC varsC bodyC] (poly;polymorphic Codec<JSON,?>//decode)]
+ (wrap (` (: (All [(~@ varsC)]
+ (-> (~@ (L/map (|>. (~) ..;Reader (`)) varsC))
+ (..;Reader ((~ (poly;to-ast *env* inputT)) (~@ varsC)))))
+ (function (~ funcC) [(~@ varsC)]
+ (~ bodyC))))))
+ poly;bound
+ poly;recursive-call
## If all else fails...
- (macro;fail ($_ text/append "Cannot create JSON decoder for: " (type;to-text :x:)))
+ (p;fail (text/append "Cannot create JSON decoder for: " (type;to-text inputT)))
))))
-(syntax: #export (Codec<JSON,?> :x:)
+(syntax: #export (Codec<JSON,?> inputT)
{#;doc (doc "A macro for automatically producing JSON codecs."
(type: Variant
(#Case0 Bool)
@@ -404,7 +379,7 @@
(derived: (Codec<JSON,?> Record)))}
(with-gensyms [g!inputs]
- (wrap (list (` (: (Codec ..;JSON (~ :x:))
- (struct (def: (~' encode) (Codec<JSON,?>//encode (~ :x:)))
- (def: ((~' decode) (~ g!inputs)) (../reader;run (~ g!inputs) (Codec<JSON,?>//decode (~ :x:))))
+ (wrap (list (` (: (Codec ..;JSON (~ inputT))
+ (struct (def: (~' encode) (Codec<JSON,?>//encode (~ inputT)))
+ (def: ((~' decode) (~ g!inputs)) (../reader;run (~ g!inputs) (Codec<JSON,?>//decode (~ inputT))))
)))))))
diff --git a/stdlib/source/lux/macro/poly.lux b/stdlib/source/lux/macro/poly.lux
index 7af9eefc1..995cc023a 100644
--- a/stdlib/source/lux/macro/poly.lux
+++ b/stdlib/source/lux/macro/poly.lux
@@ -1,17 +1,19 @@
(;module:
[lux #- function]
- (lux (control ["M" monad #+ do Monad]
+ (lux (control [monad #+ do Monad]
[eq]
["p" parser])
+ [function]
(data [text "text/" Monoid<Text>]
- (coll [list "List/" Fold<List> Monad<List>]
+ (coll [list "L/" Fold<List> Monad<List> Monoid<List>]
[dict #+ Dict])
- [number]
+ [number "nat/" Codec<Text,Nat>]
[product]
[bool]
[maybe]
- [ident "Ident/" Eq<Ident> Codec<Text,Ident>])
- [macro #+ with-gensyms "Lux/" Monad<Lux>]
+ [ident "Ident/" Eq<Ident> Codec<Text,Ident>]
+ ["R" result])
+ [macro #+ with-gensyms]
(macro [code]
["s" syntax #+ syntax: Syntax]
(syntax ["cs" common]
@@ -20,168 +22,229 @@
[type]
))
-## [Types]
-(type: #export (Matcher a)
- (-> Type (Lux a)))
-
(type: #export Env (Dict Nat [Type Code]))
-## [Combinators]
+(type: #export (Poly a)
+ (p;Parser [Env (List Type)] a))
+
+(def: #export fresh Env (dict;new number;Hash<Nat>))
+
+(def: (run' env types poly)
+ (All [a] (-> Env (List Type) (Poly a) (R;Result a)))
+ (case (p;run [env types] poly)
+ (#R;Error error)
+ (#R;Error error)
+
+ (#R;Success [[env' remaining] output])
+ (case remaining
+ #;Nil
+ (#R;Success output)
+
+ _
+ (#R;Error (|> remaining
+ (L/map type;to-text)
+ (text;join-with ", ")
+ (text/append "Unconsumed types: "))))))
+
+(def: #export (run type poly)
+ (All [a] (-> Type (Poly a) (R;Result a)))
+ (run' fresh (list type) poly))
+
+(def: #export env
+ (Poly Env)
+ (;function [[env inputs]]
+ (#R;Success [[env inputs] env])))
+
+(def: (with-env temp poly)
+ (All [a] (-> Env (Poly a) (Poly a)))
+ (;function [[env inputs]]
+ (case (p;run [temp inputs] poly)
+ (#R;Error error)
+ (#R;Error error)
+
+ (#R;Success [[_ remaining] output])
+ (#R;Success [[env remaining] output]))))
+
+(def: #export peek
+ (Poly Type)
+ (;function [[env inputs]]
+ (case inputs
+ #;Nil
+ (#R;Error "Empty stream of types.")
+
+ (#;Cons headT tail)
+ (#R;Success [[env inputs] headT]))))
+
+(def: #export any
+ (Poly Type)
+ (;function [[env inputs]]
+ (case inputs
+ #;Nil
+ (#R;Error "Empty stream of types.")
+
+ (#;Cons headT tail)
+ (#R;Success [[env tail] headT]))))
+
+(def: #export (local types poly)
+ (All [a] (-> (List Type) (Poly a) (Poly a)))
+ (;function [[env pass-through]]
+ (case (run' env types poly)
+ (#R;Error error)
+ (#R;Error error)
+
+ (#R;Success output)
+ (#R;Success [[env pass-through] output]))))
+
+(def: (label idx)
+ (-> Nat Code)
+ (code;local-symbol (text/append "label\u0000" (nat/encode idx))))
+
+(def: #export (with-extension type poly)
+ (All [a] (-> Type (Poly a) (Poly [Code a])))
+ (;function [[env inputs]]
+ (let [current-id (dict;size env)
+ g!var (label current-id)]
+ (case (p;run [(dict;put current-id [type g!var] env)
+ inputs]
+ poly)
+ (#R;Error error)
+ (#R;Error error)
+
+ (#R;Success [[_ inputs'] output])
+ (#R;Success [[env inputs'] [g!var output]])))))
+
(do-template [<combinator> <name> <type>]
[(def: #export <combinator>
- (Matcher Unit)
- (;function [:type:]
- (case (type;un-name :type:)
+ (Poly Unit)
+ (do p;Monad<Parser>
+ [headT any]
+ (case (type;un-name headT)
<type>
- (Lux/wrap [])
+ (wrap [])
_
- (macro;fail ($_ text/append "Not " <name> " type: " (type;to-text :type:))))))]
+ (p;fail ($_ text/append "Not " <name> " type: " (type;to-text headT))))))]
[void "Void" #;Void]
[unit "Unit" #;Unit]
- )
-
-(do-template [<combinator> <name>]
- [(def: #export <combinator>
- (Matcher Unit)
- (;function [:type:]
- (case (type;un-alias :type:)
- (#;Named ["lux" <name>] _)
- (Lux/wrap [])
-
- _
- (macro;fail ($_ text/append "Not " <name> " type: " (type;to-text :type:))))))]
-
- [bool "Bool"]
- [nat "Nat"]
- [int "Int"]
- [deg "Deg"]
- [real "Real"]
- [text "Text"]
+ [bool "Bool" (#;Host "#Bool" #;Nil)]
+ [nat "Nat" (#;Host "#Nat" #;Nil)]
+ [int "Int" (#;Host "#Int" #;Nil)]
+ [deg "Deg" (#;Host "#Deg" #;Nil)]
+ [real "Real" (#;Host "#Real" #;Nil)]
+ [text "Text" (#;Host "#Text" #;Nil)]
)
(def: #export primitive
- (Matcher Type)
- (;function [:type:]
- (with-expansions
- [<primitives> (do-template [<parser> <type>]
- [(do macro;Monad<Lux>
- [_ (<parser> :type:)]
- (wrap <type>))]
-
- [void Void]
- [unit Unit]
- [bool Bool]
- [nat Nat]
- [int Int]
- [deg Deg]
- [real Real]
- [text Text])]
- ($_ macro;either
- <primitives>))))
-
-(do-template [<single> <multi> <flattener> <tag>]
- [(def: #export <single>
- (Matcher [Type Type])
- (;function [:type:]
- (case (type;un-name :type:)
- (<tag> :left: :right:)
- (Lux/wrap [:left: :right:])
-
- _
- (macro;fail ($_ text/append "Not a " (Ident/encode (ident-for <tag>)) " type: " (type;to-text :type:))))))
-
- (def: #export <multi>
- (Matcher (List Type))
- (;function [:type:]
- (let [members (<flattener> (type;un-name :type:))]
+ (Poly Type)
+ (do p;Monad<Parser>
+ [headT any]
+ (case (run headT ($_ p;either
+ void
+ unit
+ bool
+ nat
+ int
+ deg
+ real
+ text))
+ (#R;Error error)
+ (p;fail error)
+
+ (#R;Success _)
+ (wrap headT))))
+
+(do-template [<name> <flattener> <tag>]
+ [(def: #export (<name> poly)
+ (All [a] (-> (Poly a) (Poly a)))
+ (do p;Monad<Parser>
+ [headT any]
+ (let [members (<flattener> (type;un-name headT))]
(if (n.> +1 (list;size members))
- (Lux/wrap members)
- (macro;fail ($_ text/append "Not a " (Ident/encode (ident-for <tag>)) " type: " (type;to-text :type:)))))))]
+ (local members poly)
+ (p;fail ($_ text/append "Not a " (Ident/encode (ident-for <tag>)) " type: " (type;to-text headT)))))))]
- [sum sum+ type;flatten-variant #;Sum]
- [prod prod+ type;flatten-tuple #;Product]
+ [variant type;flatten-variant #;Sum]
+ [tuple type;flatten-tuple #;Product]
)
-(def: #export polymorphic
- (Matcher [(List Code) Type])
- (;function [:type:]
- (let [:type: (type;un-name :type:)]
- (case :type:
- (#;UnivQ _)
- (loop [:type: :type:]
- (case :type:
- (#;UnivQ _ :type:')
- (do macro;Monad<Lux>
- [[g!tail :type:''] (recur :type:')
- g!head (macro;gensym "type-var")]
- (wrap [(list& g!head g!tail)
- :type:'']))
-
- _
- (Lux/wrap [(;list) :type:])))
-
- _
- (macro;fail ($_ text/append "Non-polymorphic type: " (type;to-text :type:)))))))
-
-(def: #export function
- (Matcher [(List Type) Type])
- (;function [:type:]
- (:: macro;Monad<Lux> wrap (type;flatten-function (type;un-name :type:)))))
-
-(def: #export apply
- (Matcher [Type (List Type)])
- (;function [:type:]
- (do macro;Monad<Lux>
- [#let [[:func: :args:] (loop [:type: (type;un-name :type:)]
- (case :type:
- (#;Apply :arg: :func:)
- (let [[:func:' :args:] (recur :func:)]
- [:func:' (list& :arg: :args:)])
-
- _
- [:type: (;list)]))]]
- (case :args:
- #;Nil
- (macro;fail "Not a type application.")
-
- _
- (wrap [:func: (list;reverse :args:)])))))
-
-(def: #export (apply-1 name)
- (-> Ident (Matcher Type))
- (;function [:type:]
- (case (type;un-name :type:)
- (^multi (#;Apply :arg: :quant:)
- [(type;un-alias :quant:) (#;Named actual _)]
- (Ident/= name actual))
- (Lux/wrap :arg:)
-
- _
- (macro;fail ($_ text/append "Not " (Ident/encode name) " type: " (type;to-text :type:))))))
-
-(def: #export (apply-2 name)
- (-> Ident (Matcher [Type Type]))
- (;function [:type:]
- (case (type;un-name :type:)
- (^multi (#;Apply :arg1: (#;Apply :arg0: :quant:))
- [(type;un-alias :quant:) (#;Named actual _)]
- (Ident/= name actual))
- (Lux/wrap [:arg0: :arg1:])
-
- _
- (macro;fail ($_ text/append "Not " (Ident/encode name) " type: " (type;to-text :type:))))))
-
-(def: #export recursive
- (Matcher Type)
- (;function [:type:]
- (case (type;un-name :type:)
- (#;Apply #;Void (#;UnivQ _ :type:'))
- (Lux/wrap :type:')
+(def: polymorphic'
+ (Poly [Nat Type])
+ (do p;Monad<Parser>
+ [headT any
+ #let [[num-arg bodyT] (type;flatten-univ-q (type;un-name headT))]]
+ (if (n.= +0 num-arg)
+ (p;fail ($_ text/append "Non-polymorphic type: " (type;to-text headT)))
+ (wrap [num-arg bodyT]))))
+
+(def: #export (polymorphic poly)
+ (All [a] (-> (Poly a) (Poly [Code (List Code) a])))
+ (do p;Monad<Parser>
+ [headT any
+ funcI (:: @ map dict;size ;;env)
+ [num-args non-poly] (local (list headT) polymorphic')
+ env ;;env
+ #let [funcL (label funcI)
+ [all-varsL env'] (loop [current-arg +0
+ env' env
+ all-varsL (: (List Code) (list))]
+ (if (n.< num-args current-arg)
+ (if (n.= +0 current-arg)
+ (let [varL (label (n.inc funcI))]
+ (recur (n.inc current-arg)
+ (|> env'
+ (dict;put funcI [headT funcL])
+ (dict;put (n.inc funcI) [(#;Bound (n.inc funcI)) varL]))
+ (#;Cons varL all-varsL)))
+ (let [partialI (|> current-arg (n.* +2) (n.+ funcI))
+ partial-varI (n.inc partialI)
+ partial-varL (label partial-varI)
+ partialC (` ((~ funcL) (~@ (|> (list;n.range +0 (n.dec num-args))
+ (L/map (|>. (n.* +2) n.inc (n.+ funcI) label))
+ list;reverse))))]
+ (recur (n.inc current-arg)
+ (|> env'
+ (dict;put partialI [;Void partialC])
+ (dict;put partial-varI [(#;Bound partial-varI) partial-varL]))
+ (#;Cons partial-varL all-varsL))))
+ [all-varsL env']))]]
+ (|> (do @
+ [output poly]
+ (wrap [funcL all-varsL output]))
+ (local (list non-poly))
+ (with-env env'))))
+
+(def: #export (function in-poly out-poly)
+ (All [i o] (-> (Poly i) (Poly o) (Poly [i o])))
+ (do p;Monad<Parser>
+ [headT any
+ #let [[inputsT outputT] (type;flatten-function (type;un-name headT))]]
+ (if (n.> +0 (list;size inputsT))
+ (p;seq (local inputsT in-poly)
+ (local (list outputT) out-poly))
+ (p;fail ($_ text/append "Non-function type: " (type;to-text headT))))))
+
+(def: #export (apply poly)
+ (All [a] (-> (Poly a) (Poly a)))
+ (do p;Monad<Parser>
+ [headT any
+ #let [[funcT paramsT] (type;flatten-application (type;un-name headT))]]
+ (if (n.= +0 (list;size paramsT))
+ (p;fail ($_ text/append "Non-application type: " (type;to-text headT)))
+ (local (#;Cons funcT paramsT) poly))))
+
+(def: #export (named expected)
+ (-> Ident (Poly Unit))
+ (do p;Monad<Parser>
+ [headT any]
+ (case (type;un-alias headT)
+ (#;Named actual _)
+ (if (Ident/= expected actual)
+ (wrap [])
+ (p;fail ($_ text/append "Not " (Ident/encode expected) " type: " (type;to-text headT))))
_
- (macro;fail ($_ text/append "Not a recursive type: " (type;to-text :type:))))))
+ (p;fail ($_ text/append "Not a named type: " (type;to-text headT))))))
(def: (adjusted-idx env idx)
(-> Env Nat Nat)
@@ -190,110 +253,110 @@
bound-idx (n.% +2 idx)]
(|> env-level n.dec (n.- bound-level) (n.* +2) (n.+ bound-idx))))
-(def: #export (bound env)
- (-> Env (Matcher Code))
- (;function [:type:]
- (case :type:
+(def: #export bound
+ (Poly Code)
+ (do p;Monad<Parser>
+ [env ;;env
+ headT any]
+ (case headT
(#;Bound idx)
(case (dict;get (adjusted-idx env idx) env)
(#;Some [poly-type poly-ast])
- (Lux/wrap poly-ast)
+ (wrap poly-ast)
#;None
- (macro;fail ($_ text/append "Unknown bound type: " (type;to-text :type:))))
+ (p;fail ($_ text/append "Unknown bound type: " (type;to-text headT))))
_
- (macro;fail ($_ text/append "Not a bound type: " (type;to-text :type:))))))
-
-(def: #export (recursion env)
- (-> Env (Matcher Code))
- (;function [:type:]
- (do macro;Monad<Lux>
- [[t-func t-args] (apply :type:)]
- (case t-func
- (^multi (#;Bound t-func-idx)
- (n.= +0 (adjusted-idx env t-func-idx))
- [(do maybe;Monad<Maybe>
- [=func (dict;get +0 env)
- =args (M;map @ (;function [t-arg]
- (case t-arg
- (#;Bound idx)
- (dict;get (adjusted-idx env idx) env)
-
- _
- #;None))
- t-args)]
- (wrap (` ((~ (product;right =func)) (~@ (List/map product;right =args))))))
- (#;Some call)])
- (wrap call)
-
- _
- (macro;fail ($_ text/append "Type is not a recursive instance: " (type;to-text :type:))))
- )))
-
-(def: #export (self env)
- (-> Env (Matcher Code))
- (;function [:type:]
- (case :type:
- (^multi (#;Apply #;Void (#;Bound t-func-idx))
- (n.= +0 (adjusted-idx env t-func-idx))
- [(dict;get +0 env)
- (#;Some [self-type self-call])])
- (Lux/wrap self-call)
+ (p;fail ($_ text/append "Not a bound type: " (type;to-text headT))))))
+
+(def: #export (var id)
+ (-> Nat (Poly Unit))
+ (do p;Monad<Parser>
+ [env ;;env
+ headT any]
+ (case headT
+ (#;Bound idx)
+ (if (n.= id (adjusted-idx env idx))
+ (wrap [])
+ (p;fail ($_ text/append "Wrong bound type.\n"
+ "Expected: " (nat/encode id) "\n"
+ " Actual: " (nat/encode idx))))
_
- (macro;fail ($_ text/append "Type is not a recursive self-call: " (type;to-text :type:))))))
+ (p;fail ($_ text/append "Not a bound type: " (type;to-text headT))))))
+
+(def: #export (recursive poly)
+ (All [a] (-> (Poly a) (Poly [Code a])))
+ (do p;Monad<Parser>
+ [headT any]
+ (case (type;un-name headT)
+ (#;Apply #;Void (#;UnivQ _ headT'))
+ (do @
+ [[recT _ output] (|> poly
+ (with-extension #;Void)
+ (with-extension headT)
+ (local (list headT')))]
+ (wrap [recT output]))
-(def: #export (var env var-id)
- (-> Env Nat (Matcher Unit))
- (;function [:type:]
- (case :type:
- (^multi (#;Bound idx)
- (n.= var-id (adjusted-idx env idx)))
- (Lux/wrap [])
+ _
+ (p;fail ($_ text/append "Not a recursive type: " (type;to-text headT))))))
+
+(def: #export recursive-self
+ (Poly Code)
+ (do p;Monad<Parser>
+ [env ;;env
+ headT any]
+ (case (type;un-name headT)
+ (^multi (#;Apply #;Void (#;Bound funcT-idx))
+ (n.= +0 (adjusted-idx env funcT-idx))
+ [(dict;get +0 env) (#;Some [self-type self-call])])
+ (wrap self-call)
_
- (macro;fail ($_ text/append "Not a bound type: " (type;to-text :type:))))))
+ (p;fail ($_ text/append "Not a recursive type: " (type;to-text headT))))))
+
+(def: #export recursive-call
+ (Poly Code)
+ (do p;Monad<Parser>
+ [env ;;env
+ [funcT argsT] (apply (p;seq any (p;many any)))
+ _ (local (list funcT) (var +0))
+ allC (let [allT (list& funcT argsT)]
+ (|> allT
+ (monad;map @ (function;const bound))
+ (local allT)))]
+ (wrap (` ((~@ allC))))))
+
+(def: #export log
+ (All [a] (Poly a))
+ (do p;Monad<Parser>
+ [current any
+ #let [_ (log! ($_ text/append
+ "{" (Ident/encode (ident-for ;;log)) "} "
+ (type;to-text current)))]]
+ (p;fail "LOGGING")))
## [Syntax]
-(def: #export (extend-env [funcT funcA] type-vars env)
- (-> [Type Code] (List [Type Code]) Env Env)
- (case type-vars
- #;Nil
- env
-
- (#;Cons [varT varA] type-vars')
- (let [current-size (dict;size env)]
- (|> env
- (dict;put current-size [funcT funcA])
- (dict;put (n.inc current-size) [varT varA])
- (extend-env [(#;Apply varT funcT) (` (#;Apply (~ varA) (~ funcA)))]
- type-vars')
- ))))
-
-(syntax: #export (poly: [_ex-lev csr;export]
- [[name env inputs] (s;form ($_ p;seq
- s;local-symbol
- s;local-symbol
- (p;many s;local-symbol)))]
+(syntax: #export (poly: [export csr;export]
+ [name s;local-symbol]
body)
- (with-gensyms [g!body]
- (let [g!inputs (List/map (|>. [""] code;symbol) inputs)
- g!name (code;symbol ["" name])
- g!env (code;symbol ["" env])]
- (wrap (;list (` (syntax: (~@ (csw;export _ex-lev)) ((~ g!name) (~@ (List/map (;function [g!input] (` [(~ g!input) s;symbol]))
- g!inputs)))
+ (with-gensyms [g!type g!output]
+ (let [g!name (code;symbol ["" name])]
+ (wrap (;list (` (syntax: (~@ (csw;export export)) ((~ g!name) [(~ g!type) s;symbol])
(do macro;Monad<Lux>
- [(~@ (List/join (List/map (;function [g!input] (;list g!input (` (macro;find-type-def (~ g!input)))))
- g!inputs)))
- (~' #let) [(~ g!env) (: Env (dict;new number;Hash<Nat>))]
- (~ g!body) (: (Lux Code)
- (loop [(~ g!env) (~ g!env)
- (~@ (List/join (List/map (;function [g!input] (;list g!input g!input))
- g!inputs)))]
- (let [(~ g!name) (~' recur)]
- (~ body))))]
- ((~' wrap) (;list (~ g!body)))))))))))
+ [(~ g!type) (macro;find-type-def (~ g!type))]
+ (case (|> (~ body)
+ (;function [(~ g!name)])
+ p;rec
+ (do p;Monad<Parser> [])
+ (;;run (~ g!type))
+ (: (;Either ;Text ;Code)))
+ (#;Left (~ g!output))
+ (macro;fail (~ g!output))
+
+ (#;Right (~ g!output))
+ ((~' wrap) (;list (~ g!output))))))))))))
(def: (common-poly-name? poly-func)
(-> Text Bool)
@@ -302,33 +365,33 @@
(def: (derivation-name poly args)
(-> Text (List Text) (Maybe Text))
(if (common-poly-name? poly)
- (#;Some (List/fold (text;replace-once "?") poly args))
+ (#;Some (L/fold (text;replace-once "?") poly args))
#;None))
-(syntax: #export (derived: [_ex-lev csr;export]
+(syntax: #export (derived: [export csr;export]
[?name (p;opt s;local-symbol)]
[[poly-func poly-args] (s;form (p;seq s;symbol (p;many s;symbol)))]
[?custom-impl (p;opt s;any)])
(do @
- [poly-args (M;map @ macro;normalize poly-args)
+ [poly-args (monad;map @ macro;normalize poly-args)
name (case ?name
(#;Some name)
(wrap name)
(^multi #;None
- [(derivation-name (product;right poly-func) (List/map product;right poly-args))
+ [(derivation-name (product;right poly-func) (L/map product;right poly-args))
(#;Some derived-name)])
(wrap derived-name)
_
- (macro;fail "derived: was given no explicit name, and cannot generate one from given information."))
+ (p;fail "derived: was given no explicit name, and cannot generate one from given information."))
#let [impl (case ?custom-impl
(#;Some custom-impl)
custom-impl
#;None
- (` ((~ (code;symbol poly-func)) (~@ (List/map code;symbol poly-args)))))]]
- (wrap (;list (` (def: (~@ (csw;export _ex-lev))
+ (` ((~ (code;symbol poly-func)) (~@ (L/map code;symbol poly-args)))))]]
+ (wrap (;list (` (def: (~@ (csw;export export))
(~ (code;symbol ["" name]))
{#;struct? true}
(~ impl)))))))
@@ -339,7 +402,7 @@
(case type
(#;Host name params)
(` (#;Host (~ (code;text name))
- (list (~@ (List/map (to-ast env) params)))))
+ (list (~@ (L/map (to-ast env) params)))))
(^template [<tag>]
<tag>
@@ -371,7 +434,7 @@
(^template [<tag> <macro> <flattener>]
(<tag> left right)
- (` (<macro> (~@ (List/map (to-ast env) (<flattener> type))))))
+ (` (<macro> (~@ (L/map (to-ast env) (<flattener> type))))))
([#;Sum | type;flatten-variant]
[#;Product & type;flatten-tuple])
@@ -380,23 +443,7 @@
(^template [<tag>]
(<tag> scope body)
- (` (<tag> (list (~@ (List/map (to-ast env) scope)))
+ (` (<tag> (list (~@ (L/map (to-ast env) scope)))
(~ (to-ast env body)))))
([#;UnivQ] [#;ExQ])
))
-
-(def: #export (gen-type env converter type-fun tvars type)
- (-> Env (-> Code Code) Code (List Code) Type Code)
- (let [type' (to-ast env type)]
- (case tvars
- #;Nil
- (converter type')
-
- _
- (` (All (~ type-fun) [(~@ tvars)]
- (-> (~@ (List/map converter tvars))
- (~ (converter (` ((~ type') (~@ tvars)))))))))))
-
-(def: #export (type-var-indices num-vars)
- (-> Nat (List Type))
- (|> num-vars list;indices (List/map (|>. #;Bound))))
diff --git a/stdlib/source/lux/macro/poly/eq.lux b/stdlib/source/lux/macro/poly/eq.lux
index 9de2a8784..20bda8be7 100644
--- a/stdlib/source/lux/macro/poly/eq.lux
+++ b/stdlib/source/lux/macro/poly/eq.lux
@@ -1,7 +1,8 @@
(;module:
lux
(lux (control [monad #+ do Monad]
- [eq])
+ [eq]
+ ["p" parser])
(data [text "text/" Monoid<Text>]
text/format
(coll [list "L/" Monad<List>]
@@ -25,109 +26,108 @@
))
## [Derivers]
-(poly: #export (Eq<?> env :x:)
- (let [->Eq (: (-> Code Code)
- (function [.type.] (` (eq;Eq (~ .type.)))))]
- (with-expansions
- [<basic> (do-template [<type> <matcher> <eq>]
- [(do @
- [_ (<matcher> :x:)]
- (wrap (` (: (~ (->Eq (` <type>)))
- <eq>))))]
+(poly: #export Eq<?>
+ (with-expansions
+ [<basic> (do-template [<type> <matcher> <eq>]
+ [(do @
+ [[primT _] (p;seq poly;peek <matcher>)]
+ (wrap (` (: (~ (@Eq primT))
+ <eq>))))]
- [Unit poly;unit (function [(~' test) (~' input)] true)]
- [Bool poly;bool bool;Eq<Bool>]
- [Nat poly;nat number;Eq<Nat>]
- [Int poly;int number;Eq<Int>]
- [Deg poly;deg number;Eq<Deg>]
- [Real poly;real number;Eq<Real>]
- [Text poly;text text;Eq<Text>])
- <composites> (do-template [<name> <eq>]
- [(do @
- [:arg: (poly;apply-1 (ident-for <name>) :x:)
- g!arg (Eq<?> env :arg:)]
- (wrap (` (: (~ (->Eq (type;to-ast :x:)))
- (<eq> (~ g!arg))))))]
+ [Unit poly;unit (function [(~' test) (~' input)] true)]
+ [Bool poly;bool bool;Eq<Bool>]
+ [Nat poly;nat number;Eq<Nat>]
+ [Int poly;int number;Eq<Int>]
+ [Deg poly;deg number;Eq<Deg>]
+ [Real poly;real number;Eq<Real>]
+ [Text poly;text text;Eq<Text>])
+ <composites> (do-template [<name> <eq>]
+ [(do @
+ [[collT [_ argC]] (p;seq poly;peek
+ (poly;apply (p;seq (poly;named (ident-for <name>))
+ Eq<?>)))]
+ (wrap (` (: (~ (@Eq collT))
+ (<eq> (~ argC))))))]
- [list;List list;Eq<List>]
- [vector;Vector vector;Eq<Vector>]
- [array;Array array;Eq<Array>]
- [queue;Queue queue;Eq<Queue>]
- [set;Set set;Eq<Set>]
- [seq;Seq seq;Eq<Seq>]
- [rose;Tree rose;Eq<Tree>]
- )]
- ($_ macro;either
+ ## [;Maybe maybe;Eq<Maybe>]
+ ## [;List list;Eq<List>]
+ [vector;Vector vector;Eq<Vector>]
+ [array;Array array;Eq<Array>]
+ [queue;Queue queue;Eq<Queue>]
+ [set;Set set;Eq<Set>]
+ [seq;Seq seq;Eq<Seq>]
+ [rose;Tree rose;Eq<Tree>]
+ )]
+ (do @
+ [*env* poly;env
+ #let [@Eq (: (-> Type Code)
+ (function [type]
+ (` (eq;Eq (~ (poly;to-ast *env* type))))))]]
+ ($_ p;either
## Primitive types
<basic>
## Composite types
<composites>
(do @
- [[:key: :val:] (poly;apply-2 (ident-for dict;Dict) :x:)
- g!val (Eq<?> env :val:)]
- (wrap (` (: (~ (->Eq (type;to-ast :x:)))
- (dict;Eq<Dict> (~ g!val))))))
+ [[collT [_ _ valC]] (p;seq poly;peek
+ (poly;apply ($_ p;seq
+ (poly;named (ident-for dict;Dict))
+ poly;any
+ Eq<?>)))]
+ (wrap (` (: (~ (@Eq collT))
+ (dict;Eq<Dict> (~ valC))))))
## Variants
- (with-gensyms [g!left g!right]
- (do @
- [members (poly;sum+ :x:)
- pattern-matching (monad;map @
- (function [[tag :case:]]
- (do @
- [g!eq (Eq<?> env :case:)]
- (wrap (list (` [((~ (code;nat tag)) (~ g!left))
- ((~ (code;nat tag)) (~ g!right))])
- (` ((~ g!eq) (~ g!left) (~ g!right)))))))
- (list;enumerate members))]
- (wrap (` (: (~ (->Eq (poly;to-ast env :x:)))
- (function [(~ g!left) (~ g!right)]
- (case [(~ g!left) (~ g!right)]
- (~@ (L/join pattern-matching)))))))))
+ (do @
+ [[variantT members] (p;seq poly;peek
+ (poly;variant (p;many Eq<?>)))
+ #let [g!left (code;local-symbol "\u0000left")
+ g!right (code;local-symbol "\u0000right")]]
+ (wrap (` (: (~ (@Eq variantT))
+ (function [(~ g!left) (~ g!right)]
+ (case [(~ g!left) (~ g!right)]
+ (~@ (L/join (L/map (function [[tag g!eq]]
+ (list (` [((~ (code;nat tag)) (~ g!left))
+ ((~ (code;nat tag)) (~ g!right))])
+ (` ((~ g!eq) (~ g!left) (~ g!right)))))
+ (list;enumerate members))))))))))
## Tuples
(do @
- [:members: (poly;prod+ :x:)
- #let [indices (|> (list;size :members:) n.dec (list;n.range +0))
+ [[tupleT g!eqs] (p;seq poly;peek
+ (poly;tuple (p;many Eq<?>)))
+ #let [indices (|> (list;size g!eqs) n.dec (list;n.range +0))
g!lefts (L/map (|>. nat/encode (text/append "left") code;local-symbol) indices)
- g!rights (L/map (|>. nat/encode (text/append "right") code;local-symbol) indices)]
- g!eqs (monad;map @ (Eq<?> env) :members:)]
- (wrap (` (: (~ (->Eq (poly;to-ast env :x:)))
+ g!rights (L/map (|>. nat/encode (text/append "right") code;local-symbol) indices)]]
+ (wrap (` (: (~ (@Eq tupleT))
(function [[(~@ g!lefts)] [(~@ g!rights)]]
(and (~@ (|> (list;zip3 g!eqs g!lefts g!rights)
(L/map (function [[g!eq g!left g!right]]
(` ((~ g!eq) (~ g!left) (~ g!right)))))))))))))
## Type recursion
- (with-gensyms [g!rec]
- (do @
- [:non-rec: (poly;recursive :x:)
- #let [new-env (poly;extend-env [:x: g!rec] (list [Bottom (` (;undefined))]) env)]
- .non-rec. (Eq<?> new-env :non-rec:)]
- (wrap (` (: (~ (poly;gen-type new-env ->Eq g!rec (list) :x:))
- (eq;rec (;function [(~ g!rec)]
- (~ .non-rec.))))))))
- (poly;self env :x:)
- (poly;recursion env :x:)
+ (do @
+ [[recT [g!self bodyC]] (p;seq poly;peek
+ (poly;recursive Eq<?>))]
+ (wrap (` (: (~ (@Eq recT))
+ (eq;rec (;function [(~ g!self)]
+ (~ bodyC)))))))
+ poly;recursive-self
## Type applications
(do @
- [[:func: :args:] (poly;apply :x:)
- .func. (Eq<?> env :func:)
- .args. (monad;map @ (Eq<?> env) :args:)]
- (wrap (` (: (~ (->Eq (type;to-ast :x:)))
- ((~ .func.) (~@ .args.))))))
+ [[funcC argsC] (poly;apply (p;seq Eq<?> (p;many Eq<?>)))]
+ (wrap (` ((~ funcC) (~@ argsC)))))
## Bound type-vars
- (poly;bound env :x:)
+ poly;bound
## Polymorphism
- (with-gensyms [g!type-fun]
- (do @
- [[g!vars :non-poly:] (poly;polymorphic :x:)
- #let [new-env (poly;extend-env [:x: g!type-fun]
- (list;zip2 (|> g!vars list;size poly;type-var-indices) g!vars)
- env)]
- .non-poly. (Eq<?> new-env :non-poly:)]
- (wrap (` (: (All (~ g!type-fun) [(~@ g!vars)]
- (-> (~@ (L/map ->Eq g!vars))
- (~ (->Eq (` ((~ (poly;to-ast env :x:)) (~@ g!vars)))))))
- (function (~ g!type-fun) [(~@ g!vars)]
- (~ .non-poly.)))))))
+ (do @
+ [[polyT [funcC varsC bodyC]] (p;seq poly;peek
+ (poly;polymorphic Eq<?>))]
+ (wrap (` (: (All [(~@ varsC)]
+ (-> (~@ (L/map (|>. (~) eq;Eq (`)) varsC))
+ (eq;Eq ((~ (poly;to-ast *env* polyT)) (~@ varsC)))))
+ (function (~ funcC) [(~@ varsC)]
+ (~ bodyC))))))
+ poly;recursive-call
## If all else fails...
- (macro;fail (format "Cannot create Eq for: " (%type :x:)))
+ (|> poly;any
+ (:: @ map (|>. %type (format "Cannot create Eq for: ") p;fail))
+ (:: @ join))
))))
diff --git a/stdlib/source/lux/macro/poly/functor.lux b/stdlib/source/lux/macro/poly/functor.lux
index 0acd49a8e..cc6007220 100644
--- a/stdlib/source/lux/macro/poly/functor.lux
+++ b/stdlib/source/lux/macro/poly/functor.lux
@@ -1,16 +1,12 @@
(;module:
lux
- (lux (control ["M" monad #+ do Monad]
- [functor])
+ (lux (control [monad #+ do Monad]
+ [functor]
+ ["p" parser])
(data [text]
text/format
- (coll [list "List/" Monad<List>]
- [dict #+ Dict])
- [number]
- [product]
- [bool]
- [maybe]
- [ident "Ident/" Codec<Text,Ident>])
+ (coll [list "L/" Monad<List> Monoid<List>])
+ [product])
[macro #+ Monad<Lux> with-gensyms]
(macro [code]
[syntax #+ syntax: Syntax]
@@ -19,107 +15,81 @@
[type]
))
-## [Derivers]
-(poly: #export (Functor<?> env :input:)
- (with-gensyms [g!type-fun g!func g!input]
- (do @
- [[g!vars :x:] (poly;polymorphic :input:)
- #let [num-vars (list;size g!vars)
- new-env (poly;extend-env [:input: g!type-fun]
- (list;zip2 (poly;type-var-indices num-vars) g!vars)
- env)]]
- (let [->Functor (: (-> Code Code)
- (function [.type.]
- (if (n.= +1 num-vars)
- (` (functor;Functor (~ .type.)))
- (let [type-params (|> num-vars n.dec list;indices (List/map (|>. %n code;local-symbol)))]
- (` (All [(~@ type-params)] (functor;Functor ((~ .type.) (~@ type-params)))))))))
- Arg<?> (: (-> Code (poly;Matcher Code))
- (function Arg<?> [value :type:]
- ($_ macro;either
- ## Nothing to do.
- (do @
- [_ (poly;primitive :type:)]
- (wrap value))
- ## Type-var
- (do @
- [_ (poly;var new-env (|> num-vars (n.* +2) n.dec) :type:)]
- (wrap (` ((~ g!func) (~ value)))))
- ## Bound type-variables
- (do @
- [_ (poly;bound new-env :type:)]
- (wrap value))
- ## Tuples/records
- (do @
- [members (poly;prod+ :type:)
- pm (M;map @
- (function [:slot:]
- (do @
- [g!slot (macro;gensym "g!slot")
- body (Arg<?> g!slot :slot:)]
- (wrap [g!slot body])))
- members)]
- (wrap (` (case (~ value)
- [(~@ (List/map product;left pm))]
- [(~@ (List/map product;right pm))])
- )))
- ## Recursion
- (do @
- [_ (poly;recursion new-env :type:)]
- (wrap (` ((~' map) (~ g!func) (~ value)))))
- )))]
- ($_ macro;either
- ## Variants
- (do @
- [cases (poly;sum+ :x:)
- pattern-matching (M;map @
- (function [[tag :case:]]
- (do @
- [synthesis (Arg<?> g!input :case:)]
- (wrap (list (` ((~ (code;nat tag)) (~ g!input)))
- (` ((~ (code;nat tag)) (~ synthesis)))))))
- (list;enumerate cases))]
- (wrap (` (: (~ (->Functor (type;to-ast :input:)))
- (struct (def: ((~' map) (~ g!func) (~ g!input))
- (case (~ g!input)
- (~@ (List/join pattern-matching)))))
- ))))
- ## Tuples/Records
- (do @
- [members (poly;prod+ :x:)
- pm (M;map @
- (function [:slot:]
+(poly: #export Functor<?>
+ (do @
+ [#let [type-funcC (code;local-symbol "\u0000type-funcC")
+ funcC (code;local-symbol "\u0000funcC")
+ inputC (code;local-symbol "\u0000inputC")]
+ *env* poly;env
+ inputT poly;peek
+ [polyC varsC non-functorT] (poly;local (list inputT)
+ (poly;polymorphic poly;any))
+ #let [num-vars (list;size varsC)]
+ #let [@Functor (: (-> Type Code)
+ (function [unwrappedT]
+ (if (n.= +1 num-vars)
+ (` (functor;Functor (~ (poly;to-ast *env* unwrappedT))))
+ (let [paramsC (|> num-vars n.dec list;indices (L/map (|>. %n code;local-symbol)))]
+ (` (All [(~@ paramsC)]
+ (functor;Functor ((~ (poly;to-ast *env* unwrappedT)) (~@ paramsC)))))))))
+ Arg<?> (: (-> Code (poly;Poly Code))
+ (function Arg<?> [valueC]
+ ($_ p;either
+ ## Type-var
+ (do p;Monad<Parser>
+ [#let [varI (|> num-vars (n.* +2) n.dec)]
+ _ (poly;var varI)]
+ (wrap (` ((~ funcC) (~ valueC)))))
+ ## Variants
(do @
- [g!slot (macro;gensym "g!slot")
- body (Arg<?> g!slot :slot:)]
- (wrap [g!slot body])))
- members)]
- (wrap (` (: (~ (->Functor (type;to-ast :input:)))
- (struct (def: ((~' map) (~ g!func) (~ g!input))
- (case (~ g!input)
- [(~@ (List/map product;left pm))]
- [(~@ (List/map product;right pm))])))
- ))))
- ## Functions
- (with-gensyms [g!out]
- (do @
- [[:ins: :out:] (poly;function :x:)
- .out. (Arg<?> g!out :out:)
- g!envs (M;seq @
- (list;repeat (list;size :ins:)
- (macro;gensym "g!envs")))]
- (wrap (` (: (~ (->Functor (type;to-ast :input:)))
- (struct (def: ((~' map) (~ g!func) (~ g!input))
- (function [(~@ g!envs)]
- (let [(~ g!out) ((~ g!input) (~@ g!envs))]
- (~ .out.))))))))))
- ## No structure (as you'd expect from Identity)
- (do @
- [_ (poly;var new-env num-vars :x:)]
- (wrap (` (: (~ (->Functor (type;to-ast :input:)))
- (struct (def: ((~' map) (~ g!func) (~ g!input))
- ((~ g!func) (~ g!input))))))))
- ## Failure...
- (macro;fail (format "Cannot create Functor for: " (%type :x:)))
- ))
- )))
+ [_ (wrap [])
+ membersC (poly;variant (p;many (Arg<?> valueC)))]
+ (wrap (` (case (~ valueC)
+ (~@ (L/join (L/map (function [[tag memberC]]
+ (list (` ((~ (code;nat tag)) (~ valueC)))
+ (` ((~ (code;nat tag)) (~ memberC)))))
+ (list;enumerate membersC))))))))
+ ## Tuples
+ (do p;Monad<Parser>
+ [pairsCC (: (poly;Poly (List [Code Code]))
+ (poly;tuple (loop [idx +0
+ pairsCC (: (List [Code Code])
+ (list))]
+ (p;either (let [slotC (|> idx %n (format "\u0000slot") code;local-symbol)]
+ (do @
+ [_ (wrap [])
+ memberC (Arg<?> slotC)]
+ (recur (n.inc idx)
+ (L/append pairsCC (list [slotC memberC])))))
+ (wrap pairsCC)))))]
+ (wrap (` (case (~ valueC)
+ [(~@ (L/map product;left pairsCC))]
+ [(~@ (L/map product;right pairsCC))]))))
+ ## Functions
+ (do @
+ [_ (wrap [])
+ #let [outL (code;local-symbol "\u0000outL")]
+ [inT+ outC] (poly;function (p;many poly;any)
+ (Arg<?> outL))
+ #let [inC+ (|> (list;size inT+) n.dec
+ (list;n.range +0)
+ (L/map (|>. %n (format "\u0000inC") code;local-symbol)))]]
+ (wrap (` (function [(~@ inC+)]
+ (let [(~ outL) ((~ valueC) (~@ inC+))]
+ (~ outC))))))
+ ## Recursion
+ (do p;Monad<Parser>
+ [_ poly;recursive-call]
+ (wrap (` ((~' map) (~ funcC) (~ valueC)))))
+ ## Bound type-variables
+ (do p;Monad<Parser>
+ [_ poly;any]
+ (wrap valueC))
+ )))]
+ [_ _ outputC] (: (poly;Poly [Code (List Code) Code])
+ (p;either (poly;polymorphic
+ (Arg<?> inputC))
+ (p;fail (format "Cannot create Functor for: " (%type inputT)))))]
+ (wrap (` (: (~ (@Functor inputT))
+ (struct (def: ((~' map) (~ funcC) (~ inputC))
+ (~ outputC))))))))
diff --git a/stdlib/test/test/lux/macro/poly/eq.lux b/stdlib/test/test/lux/macro/poly/eq.lux
index 44ecbff1e..367ac1674 100644
--- a/stdlib/test/test/lux/macro/poly/eq.lux
+++ b/stdlib/test/test/lux/macro/poly/eq.lux
@@ -6,7 +6,9 @@
(data text/format
[bool]
[number "i/" Number<Int>]
- [text])
+ [text]
+ [maybe]
+ (coll [list]))
["r" math/random]
[macro]
(macro [poly #+ derived:]
diff --git a/stdlib/test/test/lux/macro/poly/functor.lux b/stdlib/test/test/lux/macro/poly/functor.lux
index 11cdcf824..45e54bae7 100644
--- a/stdlib/test/test/lux/macro/poly/functor.lux
+++ b/stdlib/test/test/lux/macro/poly/functor.lux
@@ -3,11 +3,13 @@
(lux [io]
(control [monad #+ do Monad]
[functor]
- [eq #+ Eq])
+ [eq #+ Eq]
+ [state])
(data text/format
[bool]
[number "i/" Number<Int>]
- [text])
+ [text]
+ [identity])
["r" math/random]
[macro]
(macro [poly #+ derived:]
@@ -15,23 +17,14 @@
lux/test)
## [Utils]
-(type: (My-Maybe a)
- #My-None
- (#My-Some a))
+(derived: (&;Functor<?> ;Maybe))
-(type: (My-List a)
- #My-Nil
- (#My-Cons [a (My-List a)]))
+(derived: (&;Functor<?> ;List))
-(type: (My-State s a)
- (-> s [s a]))
+(derived: (&;Functor<?> state;State))
-(derived: (&;Functor<?> My-Maybe))
-
-(derived: (&;Functor<?> My-List))
-
-(derived: (&;Functor<?> My-State))
+(derived: (&;Functor<?> identity;Identity))
## [Tests]
-(context: "Functor polytypism"
+(context: "Functor polytypism."
(test "" true))