Normalize lambdas to be single arguments only
[scheme.git] / typecheck.scm
index 0e4e265f2d2a47f81b8a13ea4ade24914c3b33a1..98d1cf449fdaeed5f1b0f1eb22abf60a405d3a66 100644 (file)
@@ -1,18 +1,13 @@
-(define (app? x)
-  (and (list? x) (>= (length x) 2) (not (eq? (car x) 'lambda))))
-
-(define (lambda? x)
-  (and (list? x) (eq? (car x) 'lambda)))
-
-(define lambda-arg caadr)
-(define lambda-body caddr)
-
+(load "ast.scm")
                                        ; ('a, ('b, 'a))
-(define (env-lookup env x)
+(define (env-lookup env n)
   (if (null? env) (error #f "empty env")                       ; it's a type equality
-      (if (eq? (caar env) x)
+      (if (eq? (caar env) n)
          (cdar env)
-         (env-lookup (cdr env) x))))
+         (env-lookup (cdr env) n))))
+
+(define (env-insert env n t)
+  (cons (cons n t) env))
 
 (define abs-arg cadr)
 
     (string->symbol
      (string-append "t" (number->string (- cur-tvar 1))))))
 
+(define (last xs)
+  (if (null? (cdr xs))
+      (car xs)
+      (last (cdr xs))))
+
                                        
 (define (normalize prog) ; (+ a b) -> ((+ a) b)
   (cond
-   ((lambda? prog) '(lambda (lambda-arg prog) (normalize (lambda-body prog))))
+   ; (lambda (x y) (+ x y)) -> (lambda (x) (lambda (y) (+ x y)))
+   ((lambda? prog)
+    (if (> (length (lambda-args prog)) 1)
+       (list 'lambda (list (car (lambda-args prog)))
+             (normalize (list 'lambda (cdr (lambda-args prog)) (caddr prog))))
+       (list 'lambda (lambda-args prog) (normalize (caddr prog)))))
    ((app? prog)
     (if (null? (cddr prog))
        (cons (normalize (car prog)) (normalize (cdr prog))) ; (f a)
-       (normalize (cons (cons (car prog) (list (cadr prog))) (cddr prog))))) ; (f a b)
+       (list (list (normalize (car prog)) (normalize (cadr prog))) (normalize (caddr prog))))) ; (f a b)
+   ((let? prog)
+    (append (list 'let
+                 (map (lambda (x) (cons (car x) (normalize (cdr x))))
+                      (let-bindings prog)))
+           (map normalize (let-body prog))))
    (else prog)))
 
 
+; we typecheck the lambda calculus only (only single arg lambdas)
 (define (typecheck prog)
   (define (check env x)
+    (display "check: ")
+    (display x)
+    (display "\n\t")
+    (display env)
+    (newline)
     (let
        ((res
          (cond
           ((eq? x '+)   (list '() '(abs int (abs int int))))
           ((symbol? x)  (list '() (env-lookup env x)))
 
+          ((let? x)
+           (let ((new-env (fold-left
+                           (lambda (acc bind)
+                             (let ((t (check
+                                       (env-insert acc (car bind) (fresh-tvar))
+                                       (cadr bind))))
+                               (env-insert acc (car bind) (cadr t))))
+                           env (let-bindings x))))
+             (check new-env (last (let-body x)))))
+                 
+
           ((lambda? x)
-           (let* ((new-env (cons (cons (lambda-arg x) (fresh-tvar)) env))
+           (let* ((new-env (env-insert env (lambda-arg x) (fresh-tvar)))
                   (body-type-res (check new-env (lambda-body x)))
                   (subd-env (substitute-env (car body-type-res) new-env)))
-             ;; (display "lambda: ")
-             ;; (display body-type-res)
-             ;; (display "\n")
-             ;; (display subd-env)
-             ;; (display "\n")
+             (display "lambda: ")
+             (display body-type-res)
+             (display "\n")
+             (display subd-env)
+             (display "\n")
              (list (car body-type-res)
                    (list 'abs
                          (env-lookup subd-env (lambda-arg x))
              (if (abs? resolved-func-type)
                  (let ((return-type (substitute cs (caddr resolved-func-type))))
                    (list cs return-type))
-                 (error #f "wah")))))))
-      ;; (display "result of ")
-      ;; (display x)
-      ;; (display ":\n\t")
-      ;; (display (cadr res))
-      ;; (display "[")
-      ;; (display (car res))
-      ;; (display "]\n")
+                 (error #f "not a function")))))))
+      (display "result of ")
+      (display x)
+      (display ":\n\t")
+      (display (cadr res))
+      (display "[")
+      (display (car res))
+      (display "]\n")
       res))
   (cadr (check '() (normalize prog))))
 
                                        ; TODO: what's the most appropriate substitution?
                                        ; should all constraints just be limited to a pair?
 (define (substitute cs t)
-  (define (blah c)
+                                       ; gets the first concrete type
+                                       ; otherwise returns the last type variable
+  (define (get-concrete c)
     (if (null? (cdr c))
        (car c)
        (if (not (tvar? (car c)))
            (car c)
-           (blah (cdr c)))))
+           (get-concrete (cdr c)))))
   (fold-left
    (lambda (t c)
      (if (member t c)
-        (blah c)
+        (get-concrete c)
         t))
    t cs))