aboutsummaryrefslogtreecommitdiff
path: root/src/lang/type.clj
blob: 2f708867ecff6bdb0beecc0b8545fcf4f5133ba8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
(ns lang.type
  (:refer-clojure :exclude [resolve])
  (:require [clojure.core.match :refer [match]]
            [lang.util :as &util :refer [exec return* return fail fail*
                                         repeat-m try-m try-all-m map-m
                                         apply-m]]))

;; [Util]
(def ^:private success (return nil))

(defn ^:private resolve [id]
  (fn [state]
    (if-let [top+bottom (get-in state [::mappings id])]
      [::&util/ok [state top+bottom]]
      [::&util/failure (str "Unknown type-var: " id)])))

(defn ^:private update [id top bottom]
  (fn [state]
    (if-let [top+bottom (get-in state [::mappings id])]
      [::&util/ok [(assoc-in state [::mappings id] [top bottom]) nil]]
      [::&util/failure (str "Unknown type-var: " id)])))

;; [Interface]
(def +init+ {::counter 0
             ::mappings {}})

(def fresh-var
  (fn [state]
    (let [id (::counter state)]
      [::&util/ok [(-> state
                       (update-in [::counter] inc)
                       (assoc-in [::mappings id] [::any ::nothing]))
                   [::var id]]])))

(defn fresh-function [num-args]
  (exec [=args (map-m (constantly fresh-var) (range num-args))
         =return fresh-var
         :let [=function [::function =args =return]]]
    (return [=function =args =return])))

(defn solve [expected actual]
  (match [expected actual]
    [::any _]
    success

    [_ ::nothing]
    success

    [_ [::var ?id]]
    (exec [[=top =bottom] (resolve ?id)]
      (try-all-m [(exec [_ (solve expected =top)]
                    success)
                  (exec [_ (solve =top expected)
                         _ (solve expected =bottom)
                         _ (update ?id expected =bottom)]
                    success)]))

    [[::var ?id] _]
    (exec [[=top =bottom] (resolve ?id)]
      (try-all-m [(exec [_ (solve =bottom actual)]
                    success)
                  (exec [_ (solve actual =bottom)
                         _ (solve =top actual)
                         _ (update ?id =top actual)]
                    success)]))

    [_ _]
    (fail (str "Can't solve types: " (pr-str expected actual)))
    ))

(defn clean [type]
  (match type
    [::var ?id]
    (exec [[=top =bottom] (resolve ?id)]
      (clean =top))

    [::function ?args ?return]
    (exec [=args (map-m clean ?args)
           =return (clean ?return)]
      (return [::function =args =return]))

    _
    (return type)))