(;module: lux (lux (control monad) (data [maybe] [text] text/format (coll [list "list/" Fold Monoid Monad])) [meta #+ Monad] (meta [type] (type ["tc" check]))) (luxc ["&" base] (lang ["la" analysis #+ Analysis]) ["&;" scope] (analyser ["&;" common] ["&;" inference]))) ## [Analysers] (def: #export (analyse-function analyse func-name arg-name body) (-> &;Analyser Text Text Code (Meta Analysis)) (do Monad [functionT meta;expected-type] (loop [expected functionT] (&;with-stacked-errors (function [_] (format "Functions require function types: " (type;to-text expected))) (case expected (#;Named name unnamedT) (recur unnamedT) (#;Apply argT funT) (case (type;apply (list argT) funT) (#;Some value) (recur value) #;None (&;fail (format "Cannot apply type " (%type funT) " to type " (%type argT)))) (#;UnivQ _) (do @ [[var-id var] (&;with-type-env tc;existential)] (recur (maybe;assume (type;apply (list var) expected)))) (#;ExQ _) (&common;with-var (function [[var-id var]] (recur (maybe;assume (type;apply (list var) expected))))) (#;Var id) (do @ [? (&;with-type-env (tc;bound? id))] (if ? (do @ [expected' (&;with-type-env (tc;read id))] (recur expected')) ## Inference (&common;with-var (function [[input-id inputT]] (&common;with-var (function [[output-id outputT]] (do @ [#let [funT (#;Function inputT outputT)] funA (recur funT) funT' (&;with-type-env (tc;clean output-id funT)) concrete-input? (&;with-type-env (tc;bound? input-id)) funT'' (if concrete-input? (&;with-type-env (tc;clean input-id funT')) (wrap (type;univ-q +1 (&inference;replace-var input-id +1 funT')))) _ (&;with-type-env (tc;check expected funT''))] (wrap funA)) )))))) (#;Function inputT outputT) (<| (:: @ map (|>. #la;Function)) &;with-scope ## Functions have access not only to their argument, but ## also to themselves, through a local variable. (&scope;with-local [func-name functionT]) (&scope;with-local [arg-name inputT]) (&;with-expected-type outputT) (analyse body)) _ (&;fail "") ))))) (def: #export (analyse-apply analyse funcT funcA args) (-> &;Analyser Type Analysis (List Code) (Meta Analysis)) (&;with-stacked-errors (function [_] (format "Cannot apply function " (%type funcT) " to args: " (|> args (list/map %code) (text;join-with " ")))) (do Monad [expected meta;expected-type [applyT argsA] (&inference;apply-function analyse funcT args) _ (&;with-type-env (tc;check expected applyT))] (wrap (la;apply argsA funcA)))))