1+ #lang racket
2+
3+ ;; type TypeEnv = (Listof (List Variable Type))
4+
5+ ;; type Type =
6+ ;; | 'Bool
7+ ;; | 'Int
8+ ;; | `(,Type -> ,Type)
9+ ;; | TVariable
10+
11+ ;; type TVariable = Symbol (except 'Bool or 'Int)
12+
13+ ;; type Expr =
14+ ;; | Integer
15+ ;; | Boolean
16+ ;; | `(λ (,Variable) ,Expr)
17+ ;; | `(,Expr ,Expr)
18+
19+ ;; type Constraints = (Listof (List Type Type))
20+ ;; Interp: a set of equality constraints between each pair of types in the list
21+
22+
23+ ;; TypeEnv Expr -> (Maybe Type)
24+ (define (type-infer G e)
25+ (match (type-constraints G e)
26+ [(list t C)
27+ (maybe-apply apply-solution (unify C) t)]))
28+
29+ ;; TypeEnv Expr -> (List TVariable Constraints)
30+ (define (type-constraints G e)
31+ (match e
32+ [#t '(Bool ())]
33+ [#f '(Bool ())]
34+ [(? integer?) '(Int ())]
35+ [(? symbol? x) (list (lookup x G) '() )]
36+ [`(λ (,x) ,e)
37+ (let ((t1 (gensym)))
38+ (match (type-constraints (cons (list x t1) G) e)
39+ [(list t2 C)
40+ (let ((t (gensym)))
41+ (list t (append `((,t (,t1 -> ,t2))) C)))]))]
42+ [`(,e0 ,e1)
43+ (match (type-constraints G e0)
44+ [(list t0 C0)
45+ (match (type-constraints G e1)
46+ [(list t1 C1)
47+ (let ((t (gensym)))
48+ (list t (append `((,t0 (,t1 -> ,t))) C0 C1)))])])]))
49+
50+ ;; Is x a type variable? (a symbol that's not 'Int or 'Bool)
51+ (define (tvariable? x)
52+ (and (symbol? x)
53+ (not (memq x '(Bool Int)))))
54+
55+ ;; type Subst = (Listof (List TVariable Type))
56+ ;; Invariant: no variable in lhs occurs in any term earlier in the list
57+
58+ ;; Constraints -> (Maybe Subst)
59+ (define (unify C)
60+ (match C
61+ ['() '() ]
62+ [(cons (list T1 T2) C)
63+ (let ((s1 (unify C)))
64+ (let ((s2 (maybe-apply unify-one
65+ (maybe-apply apply-solution s1 T1)
66+ (maybe-apply apply-solution s1 T2))))
67+ (maybe-apply append s1 s2)))]))
68+
69+ ;; Type Type -> (Maybe Subst)
70+ ;; Generate a substitution which unifies T1 and T2 (if possible)
71+ (define (unify-one T1 T2)
72+ (if (eq? T1 T2)
73+ '()
74+ (match* (T1 T2)
75+ [(`(,T1 -> ,T2) `(,T3 -> ,T4))
76+ (unify `((,T1 ,T3) (,T2 ,T4)))]
77+ [((? tvariable? t) T)
78+ (and (not (occurs? t T))
79+ `((,t ,T)))]
80+ [(T (? tvariable? t))
81+ (and (not (occurs? t T))
82+ `((,t ,T)))]
83+ [(_ _ ) #f ])))
84+
85+ ;; TVariable Type -> Boolean
86+ ;; Does t occur in T?
87+ (define (occurs? t T)
88+ (match T
89+ [(? tvariable? y) (eq? t y)]
90+ [`(,T1 -> ,T2) (or (occurs? t T1)
91+ (occurs? t T2))]
92+ [_ #f ]))
93+
94+ ;; X (Maybe (Listof X)) -> (Maybe (Listof X))
95+ (define (maybe-cons x mxs)
96+ (and mxs (cons x mxs)))
97+
98+ ;; (X ... -> Z) (Maybe X) ... -> (Maybe Z)
99+ (define (maybe-apply f . xs)
100+ (and (andmap identity xs) (apply f xs)))
101+
102+
103+ ;; Solution Type -> Type
104+ (define (apply-solution s T)
105+ (match s
106+ ['() T]
107+ [(cons (list t T*) s)
108+ (apply-solution s (subst-type T* t T))]))
109+
110+ ;; Type Symbol Constaints -> Contraints
111+ ;; Substitute T for t in C
112+ (define (subst T t C)
113+ (map (λ (c) (map (λ (T*) (subst-type T t T*)) c))
114+ C))
115+
116+ ;; Type Symbol Type -> Type
117+ ;; Substitute T for t in T*
118+ (define (subst-type T t T*)
119+ (match T*
120+ ['Bool 'Bool ]
121+ ['Int 'Int ]
122+ [(? symbol? t*) (if (equal? t t*) T T*)]
123+ [`(,t1 -> ,t2)
124+ `(,(subst-type T t t1) -> ,(subst-type T t t2))]))
125+
126+
127+
128+
129+
130+
131+
132+
133+
134+ #|
135+ ;; Constraints -> Boolean
136+ (define (unifiable? C)
137+ (match C
138+ ['() #t]
139+ [(cons (list (? variable? t) T) C)
140+ (unifiable? (subst T t C))]
141+ [(cons (list T (? variable? t)) C)
142+ (unifiable? (subst T t C))]
143+ [(cons (list T1 T2) C)
144+ (if (equal? T1 T2)
145+ (unifiable? C)
146+ (match* (T1 T2)
147+ [(`(,T3 -> ,T4) `(,T5 -> ,T6))
148+ (unifiable? (append `((,T3 ,T5) (,T4 ,T6)) C))]
149+ [(_ _) #f]))]))
150+ |#
151+
152+
153+
154+ #|
155+ ;; type Type =
156+ ;; | 'Bool
157+ ;; | 'Int
158+ ;; | `(,Type -> ,Type)
159+
160+ ;; type Expr =
161+ ;; | Integer
162+ ;; | Boolean
163+ ;; | `(λ (,Variable : ,Type) ,Expr)
164+ ;; | `(,Expr ,Expr)
165+
166+ ;; TypeEnv Expr Type -> Bool
167+ (define (type-check G e T)
168+ (equal? (type-infer G e) T))
169+
170+ ;; TypeEnv Expr -> (Maybe Type)
171+ (define (type-infer G e)
172+ (match e
173+ [#t 'Bool]
174+ [#f 'Bool]
175+ [(? symbol? x)
176+ (lookup x G)]
177+ [(? integer?) 'Int]
178+ [`(λ (,x : ,t) ,e)
179+ (match (type-infer (cons (list x t) G) e)
180+ [#f #f]
181+ [t2 `(,t -> ,t2)])]
182+ [`(,e0 ,e1)
183+ (match (type-infer G e0)
184+ [`(,t1 -> ,t2)
185+ (match (type-infer G e1)
186+ [#f #f]
187+ [t3 (and (equal? t1 t3) t2)])]
188+ [_ #f])]))
189+ |#
190+
191+ ;; TypeEnv Expr Type -> Boolean
192+ #;
193+ (define (type-check G e T)
194+ (match e
195+ [#t (match T
196+ ['Bool #t ]
197+ [_ #f ])]
198+ [#f (match T
199+ ['Bool #t ]
200+ [_ #f ])]
201+ [(? integer?)
202+ (match T
203+ ['Int #t ]
204+ [_ #f ])]
205+
206+ [(? symbol? x)
207+ (equal? (lookup x G) T)]
208+
209+ #;
210+ ;; Doesn't work because we don't know what T0 should be...
211+ [`(,e0 ,e1)
212+ (and
213+ (type-check G e0 `(,T0 -> ,T))
214+ (type-check G e1 ,T0))]
215+
216+ [`(λ (,x) ,e)
217+ (match T
218+ [`(,T1 -> ,T2) (type-check (cons (list 'x T1) G) e T2)]
219+ [_ #f ])]))
220+
221+ ;; Variable TypeEnv -> (Maybe Type)
222+ (define (lookup x G)
223+ (match G
224+ ['() #f ]
225+ [(cons (list y T) G)
226+ (if (equal? x y)
227+ T
228+ (lookup x G))]))
229+
230+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
231+
232+ ;; Another approach: always infer
233+
234+ ;; type Type =
235+ ;; | Symbol
236+ ;; | 'Bool
237+ ;; | 'Int
238+ ;; | `(,Type -> ,Type)
239+
240+
241+
242+
243+
244+
245+
246+
247+
248+
249+
250+
251+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
252+
253+
254+ ;; Another approach: type annotations, bidirectional checking
255+
256+ ;; type Expr =
257+ ;; | Integer
258+ ;; | Boolean
259+ ;; | `(λ (,Variable) ,Expr)
260+ ;; | `(,Expr ,Expr)
261+ ;; | `(: ,Expr ,Type)
262+ #|
263+ ;; TypeEnv Expr Type -> (Maybe Type)
264+ (define (type-check G e t)
265+ (and (equal? (type-infer G e) t) t))
266+
267+ ;; TypeEnv Expr -> (Maybe Type)
268+ (define (type-infer G e)
269+ (match e
270+ [#t 'Bool]
271+ [#f 'Bool]
272+ [_ #f]))
273+
274+ |#
275+
276+
277+
278+
279+
280+
281+
282+
283+
284+
285+
286+
287+
288+
289+
290+
291+
292+
293+
294+
295+
296+
297+
298+
299+
300+
301+
302+
303+
304+
305+
306+
307+
308+
309+
310+
311+
312+
313+
314+
315+
316+
317+ #|
318+
319+ ;; TypeEnv Expr Type -> (Maybe Type)
320+ (define (type-check G e t)
321+ (match e
322+ [`(λ (,x) ,e)
323+ (match t
324+ [`(,t0 -> ,t1)
325+ (and (type-check (cons (list x t0) G) e t1) t)]
326+ [_ #f])]
327+ [_
328+ (and (equal? (type-infer G e) t) t)]))
329+
330+ ;; TypeEnv Expr -> (Maybe Type)
331+ (define (type-infer G e)
332+ (match e
333+ [#t 'Bool]
334+ [#f 'Bool]
335+ [(? integer?) 'Int]
336+ [(? symbol? x) (lookup x G)]
337+ [`(: ,e ,t) (type-check G e t)]
338+ [`(,e0 ,e1)
339+ (match (type-infer G e0)
340+ [`(,t0 -> ,t1) (and (type-check G e1 t0) t1)]
341+ [_ #f])]
342+ [_ #f]))
343+
344+ |#
345+
346+
347+
348+
349+
0 commit comments