(;module: {#;doc "Basic functionality for working with types."} [lux #- function] (lux (control [eq #+ Eq] ["M" monad #+ do Monad]) (data [text "Text/" Monoid Eq] [ident "Ident/" Eq] [number "Nat/" Codec] [maybe] (coll [list #+ "List/" Monad Monoid Fold])) (macro [code]) )) ## [Utils] (def: (beta-reduce env type) (-> (List Type) Type Type) (case type (#;Host name params) (#;Host name (List/map (beta-reduce env) params)) (^template [] ( left right) ( (beta-reduce env left) (beta-reduce env right))) ([#;Sum] [#;Product] [#;Function] [#;Apply]) (^template [] ( old-env def) (case old-env #;Nil ( env def) _ type)) ([#;UnivQ] [#;ExQ]) (#;Bound idx) (default (error! (Text/append "Unknown type var: " (Nat/encode idx))) (list;nth idx env)) _ type )) ## [Structures] (struct: #export _ (Eq Type) (def: (= x y) (case [x y] [(#;Host xname xparams) (#;Host yname yparams)] (and (Text/= xname yname) (n.= (list;size yparams) (list;size xparams)) (List/fold (;function [[x y] prev] (and prev (= x y))) true (list;zip2 xparams yparams))) (^template [] [ ] true) ([#;Void] [#;Unit]) (^template [] [( xid) ( yid)] (n.= yid xid)) ([#;Var] [#;Ex] [#;Bound]) (^or [(#;Function xleft xright) (#;Function yleft yright)] [(#;Apply xleft xright) (#;Apply yleft yright)]) (and (= xleft yleft) (= xright yright)) [(#;Named xname xtype) (#;Named yname ytype)] (and (Ident/= xname yname) (= xtype ytype)) (^template [] [( xL xR) ( yL yR)] (and (= xL yL) (= xR yR))) ([#;Sum] [#;Product]) (^or [(#;UnivQ xenv xbody) (#;UnivQ yenv ybody)] [(#;ExQ xenv xbody) (#;ExQ yenv ybody)]) (and (n.= (list;size yenv) (list;size xenv)) (= xbody ybody) (List/fold (;function [[x y] prev] (and prev (= x y))) true (list;zip2 xenv yenv))) _ false ))) ## [Values] (do-template [ ] [(def: #export ( type) (-> Type [Nat Type]) (loop [num-args +0 type type] (case type ( env sub-type) (recur (n.inc num-args) sub-type) _ [num-args type])))] [flatten-univ-q #;UnivQ] [flatten-ex-q #;ExQ] ) (def: #export (flatten-function type) (-> Type [(List Type) Type]) (case type (#;Function in out') (let [[ins out] (flatten-function out')] [(list& in ins) out]) _ [(list) type])) (def: #export (flatten-application type) (-> Type [Type (List Type)]) (case type (#;Apply arg func') (let [[func args] (flatten-application func')] [func (List/append args (list arg))]) _ [type (list)])) (do-template [ ] [(def: #export ( type) (-> Type (List Type)) (case type ( left right) (list& left ( right)) _ (list type)))] [flatten-variant #;Sum] [flatten-tuple #;Product] ) (def: #export (apply params func) (-> (List Type) Type (Maybe Type)) (case params #;Nil (#;Some func) (#;Cons param params') (case func (^template [] ( env body) (|> body (beta-reduce (list& func param env)) (apply params'))) ([#;UnivQ] [#;ExQ]) (#;Apply A F) (apply (list& A params) F) (#;Named name unnamed) (apply params unnamed) _ #;None))) (def: #export (to-ast type) (-> Type Code) (case type (#;Host name params) (` (#;Host (~ (code;text name)) (list (~@ (List/map to-ast params))))) (^template [] (` )) ([#;Void] [#;Unit]) (^template [] ( idx) (` ( (~ (code;nat idx))))) ([#;Var] [#;Ex] [#;Bound]) (^template [] ( left right) (` ( (~ (to-ast left)) (~ (to-ast right))))) ([#;Function] [#;Apply]) (^template [ ] ( left right) (` ( (~@ (List/map to-ast ( type)))))) ([#;Sum | flatten-variant] [#;Product & flatten-tuple]) (#;Named name sub-type) (code;symbol name) (^template [] ( env body) (` ( (list (~@ (List/map to-ast env))) (~ (to-ast body))))) ([#;UnivQ] [#;ExQ]) )) (def: #export (to-text type) (-> Type Text) (case type (#;Host name params) (case params #;Nil ($_ Text/append "(host " name ")") _ ($_ Text/append "(host " name " " (|> params (List/map to-text) list;reverse (list;interpose " ") (List/fold Text/append "")) ")")) #;Void "Void" #;Unit "Unit" (^template [ ] ( _) ($_ Text/append (|> ( type) (List/map to-text) list;reverse (list;interpose " ") (List/fold Text/append "")) )) ([#;Sum "(| " ")" flatten-variant] [#;Product "[" "]" flatten-tuple]) (#;Function input output) (let [[ins out] (flatten-function type)] ($_ Text/append "(-> " (|> ins (List/map to-text) list;reverse (list;interpose " ") (List/fold Text/append "")) " " (to-text out) ")")) (#;Bound idx) (Nat/encode idx) (#;Var id) ($_ Text/append "⌈v:" (Nat/encode id) "⌋") (#;Ex id) ($_ Text/append "⟨e:" (Nat/encode id) "⟩") (#;Apply param fun) (let [[type-func type-args] (flatten-application type)] ($_ Text/append "(" (to-text type-func) " " (|> type-args (List/map to-text) list;reverse (list;interpose " ") (List/fold Text/append "")) ")")) (^template [ ] ( env body) ($_ Text/append "(" " {" (|> env (List/map to-text) (text;join-with " ")) "} " (to-text body) ")")) ([#;UnivQ "All"] [#;ExQ "Ex"]) (#;Named [module name] type) ($_ Text/append module ";" name) )) (def: #export (un-alias type) (-> Type Type) (case type (#;Named _ (#;Named ident type')) (un-alias (#;Named ident type')) _ type)) (def: #export (un-name type) (-> Type Type) (case type (#;Named ident type') (un-name type') _ type)) (do-template [ ] [(def: #export ( types) (-> (List Type) Type) (case types #;Nil (#;Cons type #;Nil) type (#;Cons type types') ( type ( types'))))] [variant Void #;Sum] [tuple Unit #;Product] ) (def: #export (function inputs output) (-> (List Type) Type Type) (case inputs #;Nil output (#;Cons input inputs') (#;Function input (function inputs' output)))) (def: #export (application params quant) (-> (List Type) Type Type) (case params #;Nil quant (#;Cons param params') (application params' (#;Apply param quant)))) (do-template [ ] [(def: #export ( size body) (-> Nat Type Type) (case size +0 body _ ( (list) ( (n.dec size) body))))] [univ-q #;UnivQ] [ex-q #;ExQ] ) (def: #export (quantified? type) (-> Type Bool) (case type (#;Named [module name] _type) (quantified? _type) (#;Apply A F) (default false (do maybe;Monad [applied (apply (list A) F)] (wrap (quantified? applied)))) (^or (#;UnivQ _) (#;ExQ _)) true _ false))