(;module: lux (lux (control monad ["ex" exception #+ exception:]) (data [maybe] [text] text/format (coll [list "list/" Fold Monoid Monad])) [meta] (meta [code] [type] (type ["tc" check]))) (luxc ["&" lang] (lang ["&;" scope] ["la" analysis #+ Analysis] (analysis ["&;" common] ["&;" inference]) [";L" variable #+ Variable]))) (exception: #export Invalid-Function-Type) (exception: #export Cannot-Apply-Function) ## [Analysers] (def: #export (analyse-function analyse func-name arg-name body) (-> &;Analyser Text Text Code (Meta Analysis)) (do meta;Monad [functionT meta;expected-type] (loop [expectedT functionT] (&;with-stacked-errors (function [_] (Invalid-Function-Type (%type expectedT))) (case expectedT (#;Named name unnamedT) (recur unnamedT) (#;Apply argT funT) (case (type;apply (list argT) funT) (#;Some value) (recur value) #;None (&;throw Invalid-Function-Type (%type expectedT))) (^template [ ] ( _) (do @ [[_ instanceT] (&;with-type-env )] (recur (maybe;assume (type;apply (list instanceT) expectedT))))) ([#;UnivQ tc;existential] [#;ExQ tc;var]) (#;Var id) (do @ [?expectedT' (&;with-type-env (tc;read id))] (case ?expectedT' (#;Some expectedT') (recur expectedT') _ ## Inference (do @ [[input-id inputT] (&;with-type-env tc;var) [output-id outputT] (&;with-type-env tc;var) #let [funT (#;Function inputT outputT)] funA (recur funT) _ (&;with-type-env (tc;check expectedT funT))] (wrap funA)) )) (#;Function inputT outputT) (<| (:: @ map (function [[scope bodyA]] (` ("lux function" [(~@ (list/map code;int (variableL;environment scope)))] (~ bodyA))))) &;with-scope ## Functions have access not only to their argument, but ## also to themselves, through a local variable. (&scope;with-local [func-name expectedT]) (&scope;with-local [arg-name inputT]) (&;with-type outputT) (analyse body)) _ (&;fail "") ))))) (def: #export (analyse-apply analyse funcT funcA args) (-> &;Analyser Type Analysis (List Code) (Meta Analysis)) (&;with-stacked-errors (function [_] (Cannot-Apply-Function (format " Function: " (%type funcT) "\n" "Arguments:" (|> args list;enumerate (list/map (function [[idx argC]] (format "\n " (%n idx) " " (%code argC)))) (text;join-with ""))))) (do meta;Monad [[applyT argsA] (&inference;general analyse funcT args)] (wrap (la;apply argsA funcA)))))