aboutsummaryrefslogtreecommitdiff
path: root/src/lux/type.clj
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lux/type.clj357
1 files changed, 148 insertions, 209 deletions
diff --git a/src/lux/type.clj b/src/lux/type.clj
index 1fbaa78c0..0cd839cf2 100644
--- a/src/lux/type.clj
+++ b/src/lux/type.clj
@@ -1,41 +1,50 @@
(ns lux.type
- (:refer-clojure :exclude [deref apply merge])
+ (:refer-clojure :exclude [deref apply merge bound?])
(:require [clojure.core.match :as M :refer [match matchv]]
clojure.core.match.array
[lux.base :as & :refer [|do return* return fail fail* assert! |let]]))
-;; [Util]
-(def ^:private success (return nil))
-
-(defn lookup [type]
- (matchv ::M/objects [type]
- [["lux;VarT" id]]
- (fn [state]
- (if-let [type* (->> state (&/get$ "lux;types") (&/get$ "lux;mappings") (&/|get id))]
- (return* state type*)
- (fail* (str "Unknown type-var: " id))))
+(declare show-type)
- [_]
- (fail "[Type Error] Can't lookup non-vars.")))
-
-(defn deref [id]
+;; [Util]
+(defn bound? [id]
(fn [state]
(if-let [type* (->> state (&/get$ "lux;types") (&/get$ "lux;mappings") (&/|get id))]
(matchv ::M/objects [type*]
- [["lux;Some" type]]
- (return* state type)
+ [["lux;Some" _]]
+ (return* state true)
[["lux;None" _]]
- (fail* (str "Unbound type-var: " id)))
+ (return* state false))
(fail* (str "Unknown type-var: " id)))))
-(defn reset [id type]
+(defn deref [id]
(fn [state]
- (if-let [_ (->> state (&/get$ "lux;types") (&/get$ "lux;mappings") (&/|get id))]
- (return* (&/update$ "lux;types" (fn [ts] (&/update$ "lux;mappings" #(&/|put id (&/V "lux;Some" type) %)
- ts))
- state)
- nil)
+ (let [mappings (->> state (&/get$ "lux;types") (&/get$ "lux;mappings"))]
+ (do (prn 'deref/mappings (&/->seq (&/|keys mappings)))
+ (if-let [type* (->> mappings (&/|get id))]
+ (do (prn 'deref/type* (aget type* 0))
+ (matchv ::M/objects [type*]
+ [["lux;Some" type]]
+ (return* state type)
+
+ [["lux;None" _]]
+ (fail* (str "Unbound type-var: " id))))
+ (fail* (str "Unknown type-var: " id)))))))
+
+(defn set-var [id type]
+ (fn [state]
+ (if-let [tvar (->> state (&/get$ "lux;types") (&/get$ "lux;mappings") (&/|get id))]
+ (do ;; (prn 'set-var (aget tvar 0))
+ (matchv ::M/objects [tvar]
+ [["lux;Some" bound]]
+ (fail* (str "Can't rebind type var: " id " | Current type: " (show-type bound)))
+
+ [["lux;None" _]]
+ (return* (&/update$ "lux;types" (fn [ts] (&/update$ "lux;mappings" #(&/|put id (&/V "lux;Some" type) %)
+ ts))
+ state)
+ nil)))
(fail* (str "Unknown type-var: " id)))))
;; [Exports]
@@ -50,7 +59,7 @@
(def fresh-lambda
(|do [=arg fresh-var
- =return fresh-var]
+ =return fresh-var]
(return (&/V "lux;LambdaT" (&/T =arg =return)))))
(defn clean [tvar type]
@@ -59,19 +68,18 @@
(matchv ::M/objects [type]
[["lux;VarT" ?id]]
(if (= ?tid ?id)
- (&/try-all% (&/|list (|do [=type (deref ?id)]
- (clean tvar =type))
- (return type)))
+ (|do [=type (deref ?id)]
+ (clean tvar =type))
(return type))
[["lux;LambdaT" [?arg ?return]]]
(|do [=arg (clean tvar ?arg)
- =return (clean tvar ?return)]
+ =return (clean tvar ?return)]
(return (&/V "lux;LambdaT" (&/T =arg =return))))
[["lux;AppT" [?lambda ?param]]]
(|do [=lambda (clean tvar ?lambda)
- =param (clean tvar ?param)]
+ =param (clean tvar ?param)]
(return (&/V "lux;AppT" (&/T =lambda =param))))
[["lux;TupleT" ?members]]
@@ -80,23 +88,23 @@
[["lux;VariantT" ?members]]
(|do [=members (&/map% (fn [[k v]]
- (|do [=v (clean tvar v)]
- (return (&/T k =v))))
- ?members)]
+ (|do [=v (clean tvar v)]
+ (return (&/T k =v))))
+ ?members)]
(return (&/V "lux;VariantT" =members)))
[["lux;RecordT" ?members]]
(|do [=members (&/map% (fn [[k v]]
- (|do [=v (clean tvar v)]
- (return (&/T k =v))))
- ?members)]
+ (|do [=v (clean tvar v)]
+ (return (&/T k =v))))
+ ?members)]
(return (&/V "lux;RecordT" =members)))
[["lux;AllT" [?env ?name ?arg ?body]]]
(|do [=env (&/map% (fn [[k v]]
- (|do [=v (clean tvar v)]
- (return (&/T k =v))))
- ?env)]
+ (|do [=v (clean tvar v)]
+ (return (&/T k =v))))
+ ?env)]
(return (&/V "lux;AllT" (&/T =env ?name ?arg ?body))))
[_]
@@ -112,8 +120,8 @@
[["lux;NothingT" _]]
"Nothing"
- [["lux;DataT" [name params]]]
- (str "(^ " name " [" (->> params (&/|map show-type) (&/|interpose " ") (&/fold str "")) "])")
+ [["lux;DataT" name]]
+ (str "(^ " name ")")
[["lux;TupleT" elems]]
(if (&/|empty? elems)
@@ -166,10 +174,8 @@
[["lux;NothingT" _] ["lux;NothingT" _]]
true
- [["lux;DataT" [xname xparams]] ["lux;DataT" [yname yparams]]]
- (&/fold (fn [old xy] (and old (type= (aget xy 0) (aget xy 1))))
- (= xname yname)
- (&/zip2 xparams yparams))
+ [["lux;DataT" xname] ["lux;DataT" yname]]
+ (= xname yname)
[["lux;TupleT" xelems] ["lux;TupleT" yelems]]
(&/fold (fn [old xy] (and old (type= (aget xy 0) (aget xy 1))))
@@ -261,9 +267,6 @@
[["lux;TupleT" ?members]]
(&/V "lux;TupleT" (&/|map (partial beta-reduce env) ?members))
- [["lux;DataT" [?name ?params]]]
- (&/V "lux;DataT" (&/T ?name (&/|map (partial beta-reduce env) ?params)))
-
[["lux;AppT" [?type-fn ?type-arg]]]
(&/V "lux;AppT" (&/T (beta-reduce env ?type-fn) (beta-reduce env ?type-arg)))
@@ -316,28 +319,40 @@
;; (prn 'check* (show-type expected) (show-type actual))
(matchv ::M/objects [expected actual]
[["lux;AnyT" _] _]
- success
+ (return (&/T fixpoints nil))
[_ ["lux;NothingT" _]]
- success
-
+ (return (&/T fixpoints nil))
+
+ [["lux;VarT" ?eid] ["lux;VarT" ?aid]]
+ (if (= ?eid ?aid)
+ (return (&/T fixpoints nil))
+ (&/try-all% (&/|list (|do [ebound (deref ?eid)]
+ (check* fixpoints ebound actual))
+ (|do [abound (deref ?aid)]
+ (check* fixpoints expected abound))
+ (|do [_ (set-var ?eid actual)]
+ (return (&/T fixpoints nil))))))
+
[["lux;VarT" ?id] _]
- (&/try-all% (&/|list (|do [bound (deref ?id)]
- (check* fixpoints bound actual))
- (reset ?id actual)))
+ (&/try-all% (&/|list (|do [_ (set-var ?id actual)]
+ (return (&/T fixpoints nil)))
+ (|do [bound (deref ?id)]
+ (check* fixpoints bound actual))))
[_ ["lux;VarT" ?id]]
- (&/try-all% (&/|list (|do [bound (deref ?id)]
- (check* fixpoints expected bound))
- (reset ?id expected)))
+ (&/try-all% (&/|list (|do [_ (set-var ?id expected)]
+ (return (&/T fixpoints nil)))
+ (|do [bound (deref ?id)]
+ (check* fixpoints expected bound))))
[["lux;AppT" [F A]] _]
(|do [expected* (apply-type F A)
- :let [fp-pair (&/T expected actual)]]
+ :let [fp-pair (&/T expected actual)]]
(matchv ::M/objects [(fp-get fp-pair fixpoints)]
[["lux;Some" ?]]
(if ?
- success
+ (return (&/T fixpoints nil))
(fail (check-error expected actual)))
[["lux;None" _]]
@@ -349,68 +364,72 @@
[["lux;AllT" _] _]
(|do [$var fresh-var
- expected* (apply-type expected $var)]
+ expected* (apply-type expected $var)]
(check* fixpoints expected* actual))
[_ ["lux;AllT" _]]
(|do [$var fresh-var
- actual* (apply-type actual $var)]
+ actual* (apply-type actual $var)]
(check* fixpoints expected actual*))
- [["lux;DataT" [e!name e!params]] ["lux;DataT" [a!name a!params]]]
- (cond (not= e!name a!name)
- (fail (str "[Type Error] Names don't match: " e!name " & " a!name))
-
- (not= (&/|length e!params) (&/|length a!params))
- (fail "[Type Error] Params don't match in size.")
-
- :else
- (|do [_ (&/map% (fn [ea]
- (|let [[e a] ea]
- (check* fixpoints e a)))
- (&/zip2 e!params a!params))]
- success))
+ [["lux;DataT" e!name] ["lux;DataT" a!name]]
+ (if (= e!name a!name)
+ (return (&/T fixpoints nil))
+ (fail (str "[Type Error] Names don't match: " e!name " & " a!name)))
[["lux;LambdaT" [eI eO]] ["lux;LambdaT" [aI aO]]]
- (|do [_ (check* fixpoints aI eI)]
- (check* fixpoints eO aO))
+ (|do [[fixpoints* _] (check* fixpoints aI eI)]
+ (check* fixpoints* eO aO))
[["lux;TupleT" e!members] ["lux;TupleT" a!members]]
- (if (= (&/|length e!members) (&/|length a!members))
- (|do [_ (&/map% (fn [ea]
- (|let [[e a] ea]
- (do ;; (prn "lux;TupleT" 'ITER (show-type e) (show-type a))
- (check* fixpoints e a))))
- (&/zip2 e!members a!members))
- ;; :let [_ (prn "lux;TupleT" 'DONE)]
- ]
- success)
- (do ;; (prn "lux;TupleT" (&/|length e!members) (&/|length a!members))
- ;; (prn "lux;TupleT"
- ;; (&/fold str "" (&/|interpose " " (&/|map show-type e!members)))
- ;; (&/fold str "" (&/|interpose " " (&/|map show-type a!members))))
- ;; (prn "lux;TupleT#fail" (fail "[Type Error] Tuples don't match in size."))
- (fail "[Type Error] Tuples don't match in size.")))
+ (do (do (prn 'e!members (&/|length e!members))
+ (prn 'a!members (&/|length a!members)))
+ (if (= (&/|length e!members) (&/|length a!members))
+ (|do [fixpoints* (&/fold% (fn [fixp ea]
+ (|let [[e a] ea]
+ (do ;; (prn "lux;TupleT" 'ITER (show-type e) (show-type a))
+ (|do [[fixp* _] (check* fixp e a)]
+ (return fixp*)))))
+ fixpoints
+ (&/zip2 e!members a!members))
+ ;; :let [_ (prn "lux;TupleT" 'DONE)]
+ ]
+ (return (&/T fixpoints* nil)))
+ (do ;; (prn "lux;TupleT" (&/|length e!members) (&/|length a!members))
+ ;; (prn "lux;TupleT"
+ ;; (&/fold str "" (&/|interpose " " (&/|map show-type e!members)))
+ ;; (&/fold str "" (&/|interpose " " (&/|map show-type a!members))))
+ ;; (prn "lux;TupleT#fail" (fail "[Type Error] Tuples don't match in size."))
+ (fail "[Type Error] Tuples don't match in size."))))
[["lux;VariantT" e!cases] ["lux;VariantT" a!cases]]
- (|do [_ (&/map% (fn [kv]
- (|let [[k av] kv]
- (if-let [ev (&/|get k e!cases)]
- (check* fixpoints ev av)
- (fail (str "[Type Error] The expected variant cannot handle case: #" k)))))
- a!cases)]
- success)
+ (if (= (&/|length e!cases) (&/|length a!cases))
+ (|do [fixpoints* (&/fold% (fn [fixp slot]
+ (prn "lux;VariantT" slot)
+ (if-let [e!type (&/|get slot e!cases)]
+ (if-let [a!type (&/|get slot a!cases)]
+ (|do [[fixp* _] (check* fixp e!type a!type)]
+ (return fixp*))
+ (fail (check-error expected actual)))
+ (fail (check-error expected actual))))
+ fixpoints
+ (&/|keys e!cases))]
+ (return (&/T fixpoints* nil)))
+ (fail "[Type Error] Variants don't match in size."))
[["lux;RecordT" e!fields] ["lux;RecordT" a!fields]]
(if (= (&/|length e!fields) (&/|length a!fields))
- (|do [_ (&/map% (fn [slot]
- (if-let [e!type (&/|get e!fields slot)]
- (if-let [a!type (&/|get a!fields slot)]
- (check* fixpoints e!type a!type)
- (fail (check-error expected actual)))
- (fail (check-error expected actual))))
- (&/|keys e!fields))]
- success)
+ (|do [fixpoints* (&/fold% (fn [fixp slot]
+ (prn "lux;RecordT" slot)
+ (if-let [e!type (&/|get slot e!fields)]
+ (if-let [a!type (&/|get slot a!fields)]
+ (|do [[fixp* _] (check* fixp e!type a!type)]
+ (return fixp*))
+ (fail (check-error expected actual)))
+ (fail (check-error expected actual))))
+ fixpoints
+ (&/|keys e!fields))]
+ (return (&/T fixpoints* nil)))
(fail "[Type Error] Records don't match in size."))
[_ _]
@@ -426,7 +445,9 @@
;; ...
))
-(def check (partial check* init-fixpoints))
+(defn check [expected actual]
+ (|do [_ (check* init-fixpoints expected actual)]
+ (return nil)))
(defn apply-lambda [func param]
(matchv ::M/objects [func]
@@ -436,20 +457,30 @@
[["lux;AllT" [local-env local-name local-arg local-def]]]
(|do [$var fresh-var
- func* (apply-type func $var)]
+ func* (apply-type func $var)]
(apply-lambda func* param))
[_]
(fail (str "[Type System] Can't apply type " (show-type func) " to type " (show-type param)))
))
+(defn actual-type [type]
+ (matchv ::M/objects [type]
+ [["lux;AppT" [?all ?param]]]
+ (|do [type* (apply-type ?all ?param)]
+ (actual-type type*))
+
+ [_]
+ (return type)
+ ))
+
(def Any (&/V "lux;AnyT" nil))
(def Nothing (&/V "lux;NothingT" nil))
-(def Bool (&/V "lux;DataT" (&/T "java.lang.Boolean" (&/|list))))
-(def Int (&/V "lux;DataT" (&/T "java.lang.Long" (&/|list))))
-(def Real (&/V "lux;DataT" (&/T "java.lang.Double" (&/|list))))
-(def Char (&/V "lux;DataT" (&/T "java.lang.Character" (&/|list))))
-(def Text (&/V "lux;DataT" (&/T "java.lang.String" (&/|list))))
+(def Bool (&/V "lux;DataT" "java.lang.Boolean"))
+(def Int (&/V "lux;DataT" "java.lang.Long"))
+(def Real (&/V "lux;DataT" "java.lang.Double"))
+(def Char (&/V "lux;DataT" "java.lang.Character"))
+(def Text (&/V "lux;DataT" "java.lang.String"))
(def Unit (&/V "lux;TupleT" (&/|list)))
(def List
@@ -460,16 +491,15 @@
(&/V "lux;BoundT" "a")))))))))))
(def Type
- (let [Type (&/V "lux;AppT" (&/T (&/V "lux;BoundT" "Type") (&/V "lux;BoundT" "")))
+ (let [Type (&/V "lux;AppT" (&/T (&/V "lux;BoundT" "Type") (&/V "lux;BoundT" "_")))
TypeEnv (&/V "lux;AppT" (&/T List (&/V "lux;TupleT" (&/|list Text Type))))
Unit (&/V "lux;TupleT" (&/|list))
- TypeList (&/V "lux;AppT" (&/T List Type))
TypePair (&/V "lux;TupleT" (&/|list Type Type))]
- (&/V "lux;AppT" (&/T (&/V "lux;AllT" (&/T (&/|list) "Type" ""
+ (&/V "lux;AppT" (&/T (&/V "lux;AllT" (&/T (&/|list) "Type" "_"
(&/V "lux;VariantT" (&/|list (&/T "lux;AnyT" Unit)
(&/T "lux;NothingT" Unit)
- (&/T "lux;DataT" (&/V "lux;TupleT" (&/|list Text TypeList)))
- (&/T "lux;TupleT" TypeList)
+ (&/T "lux;DataT" Text)
+ (&/T "lux;TupleT" (&/V "lux;AppT" (&/T List Type)))
(&/T "lux;VariantT" TypeEnv)
(&/T "lux;RecordT" TypeEnv)
(&/T "lux;LambdaT" TypePair)
@@ -479,94 +509,3 @@
(&/T "lux;AppT" TypePair)
))))
(&/V "lux;NothingT" nil)))))
-
-(let [&& #(and %1 %2)]
- (defn merge [x y]
- (matchv ::M/objects [x y]
- [_ ["lux;AnyT" _]]
- (return y)
-
- [["lux;AnyT" _] _]
- (return x)
-
- [_ ["lux;NothingT" _]]
- (return x)
-
- [["lux;NothingT" _] _]
- (return y)
-
- [["lux;DataT" [xname xparams]] ["lux;DataT" [yname yparams]]]
- (if (and (= xname yname)
- (= (&/|length xparams) (&/|length yparams)))
- (fail (str "[Type System Error] Can't merge types: " (show-type x) " and " (show-type y)))
- (|do [xyparams (&/map% (fn [xy]
- (|let [[xp yp] xy]
- (merge xp yp)))
- (&/zip2 xparams yparams))]
- (return (&/V "lux;DataT" (&/T xname xyparams)))))
-
- [["lux;TupleT" xmembers] ["lux;TupleT" ymembers]]
- (if (= (&/|length xmembers) (&/|length ymembers))
- (fail (str "[Type System Error] Can't merge types: " (show-type x) " and " (show-type y)))
- (|do [xymembers (&/map% (fn [xy]
- (|let [[xp yp] xy]
- (merge xp yp)))
- (&/zip2 xmembers ymembers))]
- (return (&/V "lux;TupleT" xymembers))))
-
- [["lux;VariantT" x!cases] ["lux;VariantT" y!cases]]
- (|do [cases (&/fold% (fn [cases kv]
- (matchv ::M/objects [kv]
- [[k v]]
- (if-let [cv (&/|get k cases)]
- (|do [v* (merge cv v)]
- (return (&/|put k v* cases)))
- (return (&/|put k v cases)))))
- x!cases
- y!cases)]
- (return (&/V "lux;VariantT" cases)))
-
- [["lux;RecordT" x!fields] ["lux;RecordT" y!fields]]
- (if (= (&/|length x!fields) (&/|length y!fields))
- (|do [fields (&/fold% (fn [fields kv]
- (matchv ::M/objects [kv]
- [[k v]]
- (if-let [cv (&/|get k fields)]
- (|do [v* (merge cv v)]
- (return (&/|put k v* fields)))
- (fail (str "[Type System Error] Incompatible records: " (show-type x) " and " (show-type y))))))
- x!fields
- y!fields)]
- (return (&/V "lux;RecordT" fields)))
- (fail (str "[Type System Error] Incompatible records: " (show-type x) " and " (show-type y))))
-
- [["lux;LambdaT" [xinput xoutput]] ["lux;LambdaT" [yinput youtput]]]
- (|do [xyinput (check xinput yinput)
- xyoutput (check xoutput youtput)]
- (return (&/V "lux;LambdaT" (&/T xyinput xyoutput))))
-
- [_ _]
- (fail (str "[Type System Error] Can't merge types: " (show-type x) " and " (show-type y))))))
-
-(comment
- (do (def Real (&/V "lux;DataT" (&/T "java.lang.Long" (&/|list))))
- (def RealT (&/V "lux;VariantT" (&/|list (&/T "lux;DataT" (&/V "lux;TupleT" (&/|list Text
- (&/V "lux;VariantT" (&/|list (&/T "lux;Nil" (&/V "lux;TupleT" (&/|list)))))))))))
- )
-
- (matchv ::M/objects [((check Type RealT)
- (&/init-state nil))]
- [["lux;Left" ?msg]]
- (assert false ?msg)
-
- [_]
- (println "YEAH!"))
-
- (matchv ::M/objects [((check List (&/V "lux;AppT" (&/T List Real)))
- (&/init-state nil))]
- [["lux;Left" ?msg]]
- (assert false ?msg)
-
- [_]
- (println "YEAH!"))
- )