(.module: [lux #* [abstract [monad (#+ Monad do)]] [control ["p" parser ["<.>" type] ["s" code (#+ Parser)]]] [data ["." product] ["." bit] ["." maybe] [number ["." nat ("#@." decimal)] ["." int] ["." rev] ["." frac]] ["." text ("#@." monoid) ["%" format (#+ format)]] [collection ["." list ("#@." monad)] ["." row] ["." array] ["." queue] ["." set] ["." dictionary (#+ Dictionary)] ["." tree]]] [time ["." duration] ["." date] ["." instant] ["." day] ["." month]] [macro ["." code] ["." poly (#+ poly:)] [syntax (#+ syntax:) ["." common]]] ["." type ["." unit]]] {1 ["." /]}) (poly: #export equivalence (`` (do {! p.monad} [#let [g!_ (code.local-identifier "_____________")] *env* .env inputT .peek #let [@Equivalence (: (-> Type Code) (function (_ type) (` ((~! /.Equivalence) (~ (poly.to-code *env* type))))))]] ($_ p.either ## Basic types (~~ (template [ ] [(do ! [_ ] (wrap (` (: (~ (@Equivalence inputT)) ))))] [(.exactly Any) (function ((~ g!_) (~ g!_) (~ g!_)) #1)] [(.sub Bit) (~! bit.equivalence)] [(.sub Nat) (~! nat.equivalence)] [(.sub Int) (~! int.equivalence)] [(.sub Rev) (~! rev.equivalence)] [(.sub Frac) (~! frac.equivalence)] [(.sub Text) (~! text.equivalence)])) ## Composite types (~~ (template [ ] [(do ! [[_ argC] (.apply (p.and (.exactly ) equivalence))] (wrap (` (: (~ (@Equivalence inputT)) ( (~ argC))))))] [.Maybe (~! maybe.equivalence)] [.List (~! list.equivalence)] [row.Row (~! row.equivalence)] [array.Array (~! array.equivalence)] [queue.Queue (~! queue.equivalence)] [set.Set (~! set.equivalence)] [tree.Tree (~! tree.equivalence)] )) (do ! [[_ _ valC] (.apply ($_ p.and (.exactly dictionary.Dictionary) .any equivalence))] (wrap (` (: (~ (@Equivalence inputT)) ((~! dictionary.equivalence) (~ valC)))))) ## Models (~~ (template [ ] [(do ! [_ (.exactly )] (wrap (` (: (~ (@Equivalence inputT)) ))))] [duration.Duration duration.equivalence] [instant.Instant instant.equivalence] [date.Date date.equivalence] [day.Day day.equivalence] [month.Month month.equivalence] )) (do ! [_ (.apply (p.and (.exactly unit.Qty) .any))] (wrap (` (: (~ (@Equivalence inputT)) unit.equivalence)))) ## Variants (do ! [members (.variant (p.many equivalence)) #let [last (dec (list.size members)) g!_ (code.local-identifier "_____________") g!left (code.local-identifier "_____________left") g!right (code.local-identifier "_____________right")]] (wrap (` (: (~ (@Equivalence inputT)) (function ((~ g!_) (~ g!left) (~ g!right)) (case [(~ g!left) (~ g!right)] (~+ (list@join (list@map (function (_ [tag g!eq]) (if (nat.= last tag) (list (` [((~ (code.nat (dec tag))) #1 (~ g!left)) ((~ (code.nat (dec tag))) #1 (~ g!right))]) (` ((~ g!eq) (~ g!left) (~ g!right)))) (list (` [((~ (code.nat tag)) #0 (~ g!left)) ((~ (code.nat tag)) #0 (~ g!right))]) (` ((~ g!eq) (~ g!left) (~ g!right)))))) (list.enumeration members)))) (~ g!_) #0)))))) ## Tuples (do ! [g!eqs (.tuple (p.many equivalence)) #let [g!_ (code.local-identifier "_____________") indices (list.indices (list.size g!eqs)) g!lefts (list@map (|>> nat@encode (text@compose "left") code.local-identifier) indices) g!rights (list@map (|>> nat@encode (text@compose "right") code.local-identifier) indices)]] (wrap (` (: (~ (@Equivalence inputT)) (function ((~ g!_) [(~+ g!lefts)] [(~+ g!rights)]) (and (~+ (|> (list.zip/3 g!eqs g!lefts g!rights) (list@map (function (_ [g!eq g!left g!right]) (` ((~ g!eq) (~ g!left) (~ g!right))))))))))))) ## Type recursion (do ! [[g!self bodyC] (.recursive equivalence) #let [g!_ (code.local-identifier "_____________")]] (wrap (` (: (~ (@Equivalence inputT)) ((~! /.rec) (.function ((~ g!_) (~ g!self)) (~ bodyC))))))) .recursive-self ## Type applications (do ! [[funcC argsC] (.apply (p.and equivalence (p.many equivalence)))] (wrap (` ((~ funcC) (~+ argsC))))) ## Parameters .parameter ## Polymorphism (do ! [[funcC varsC bodyC] (.polymorphic equivalence)] (wrap (` (: (All [(~+ varsC)] (-> (~+ (list@map (|>> (~) ((~! /.Equivalence)) (`)) varsC)) ((~! /.Equivalence) ((~ (poly.to-code *env* inputT)) (~+ varsC))))) (function ((~ funcC) (~+ varsC)) (~ bodyC)))))) .recursive-call ## If all else fails... (|> .any (:: ! map (|>> %.type (format "Cannot create Equivalence for: ") p.fail)) (:: ! join)) ))))