~ashton314/microKanren

microKanren/type_checking.rkt -rw-r--r-- 1.9 KiB
1430db53Ashton Wiersdorf Trying out some type checking with errors 4 months ago
                                                                                
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
#lang racket/base

(require "kanren.rkt")

;;; Environment functions
(define (Γ-lookup Γ x τ)
  ;; The environment is modeled as a simple assoc list, mapping
  ;; variables to types. The lookup function works by relating a
  ;; variable and its environment with a type by first checking if the
  ;; first thing in the assoc list matches the variable, and if not,
  ;; proceeding recursively down the list.
  (disj (fresh (Γ*) (== Γ (cons (cons x τ) Γ*)))
        (fresh (Γ* x* τ*)
               (conj (== Γ (cons (cons x* τ*) Γ*))
                     (Γ-lookup Γ* x τ)))))

(define (Γ-extend Γ x τ Γ*)
  ;; This slaps a new pair on the front of the environment assoc list.
  (== (cons (cons x τ) Γ) Γ*))

;;; Type checker core
(define (type-for expr Γ t)
  (conde
   [(== (cons '? number?) expr) (== t 'number)]
   [(== (cons '? boolean?) expr) (== t 'boolean)]
   [(== (cons '? symbol?) expr) (Γ-lookup Γ expr t)]
   [(fresh (op)
           (== expr `(zero? ,op))
           (type-for op Γ 'number)
           (== t 'boolean))]
   [(fresh (c t-case f-case arm-type)
           (== expr `(if ,c ,t-case ,f-case))
           (type-for c Γ 'boolean)
           (type-for t-case Γ arm-type)
           (type-for f-case Γ arm-type)
           (== t arm-type))]
   [(fresh (op1 op2)
           (== expr `(+ ,op1 ,op2))
           (type-for op1 Γ 'number)
           (type-for op2 Γ 'number)
           (== t 'number))]
   [(fresh (arg body arg-type Γ* body-type)
           (conj+ (== `(lambda ,arg ,body) expr)
                  (Γ-extend Γ arg arg-type Γ*)
                  (type-for body Γ* body-type)
                  (== t (cons arg-type body-type))))]
   [(fresh (fexpr arg arg-type body-type)
           (conj+ (== expr `(,fexpr ,arg))
                  (type-for fexpr Γ (cons arg-type body-type))
                  (type-for arg Γ arg-type)
                  (== t body-type)))]))