;;
;; Further type checking tests
;;

(load "4-2.scm")

(type-check 
"
let x = 3 y = 4 in +(x,y)
") 

(type-check
"
let f = proc (int x) add1(x) in (f 4)
") 

(type-check
"
let f = proc (int x) add1(x) in f
")

(type-check
let apply = proc ((int * int -> int) f, int x) (f add1(x) x)
    g     = proc (int x, int y) *(x,y)
in (apply g 3)
")

;; wrong number of args
(type-check
"
let f = proc (int x) add1(x) in (f 4 3)
")

;; unbound variable
(type-check
"
let f = proc (int x) add1(x) in (g 4 3)
")

(type-check
"
(proc (int x) add1(x) 4)
")

(type-check
"
letrec int f(int x, int y) = +(x,y) 
in (f 40 50)
")


(type-check
"
letrec 
  int fact(int x)= if zero?(x) then 1 else *(x, (fact sub1(x)))
in fact
")

(type-check
"
letrec 
  int fact(int x)= if zero?(x) then 1 else *(x, (fact sub1(x)))
in (fact 6)
")

(type-check
"
letrec int odd(int x)  = if zero?(x) then 0 else (even sub1(x))
       int even(int x) = if zero?(x) then 1 else (odd  sub1(x))
in odd"
")

(type-check
"
letrec int odd(int x)  = if zero?(x) then 0 else (even sub1(x))
       int even(int x) = if zero?(x) then 1 else (odd  sub1(x))
in (odd 13)
")

(type-check
"
letrec int odd(int x)  = if zero?(x) then 0 else (even sub1(x))
       int even(int x) = if zero?(x) then 1 else (odd  sub1(x))
in (even odd)
") 

(type-check
"
let fix =  proc (int f)
            let d = proc (int x) proc (int z) (f (x x) z)
            in proc (int n) (f (d d) n)
    t4m = proc (int f, int x) if x then +(4,(f -(x,1))) else 0
in let times4 = (fix t4m)
   in (times4 3)
")

;;
;; lettype tests
;;
(load "4-3.scm")

(type-check
"
lettype foo = int
 foo m(int x) = add1(x)
in m
")

(type-check
"
lettype foo = int
 foo m(int x) = add1(x)
in (m 3)
")

;; foo <> int
(type-check
"
lettype foo = int
 foo m (int x) = add1(x)
in add1((m 3))
")


(type-check
"
lettype ff = (int -> int)
  ff zero-ff (int k) = 0                % a real type error!
  ff extend-ff (int k, int val, ff old-ff) =
       proc (int k1) if zero?(-(k1,k)) then val else (old-ff k1)
  int apply-ff (int k, ff f) = (f k)
in let ff1 = (extend-ff 1 11 (extend-ff 2 22 zero-ff))
   in (apply-ff ff1 2)
")

(type-check
"
lettype ff = (int -> int)
  ff zero-ff () = proc (int k) 0               
  ff extend-ff (int k, int val, ff old-ff) =
       proc (int k1) if zero?(-(k1,k)) then val else (old-ff k1)
  int apply-ff (ff f, int k) = (f k)
in let ff1 = (extend-ff 1 11 (extend-ff 2 22 (zero-ff)))
   in (apply-ff ff1 2)
")

(type-check
"
lettype ff = (int -> int)
  ff zero-ff () = proc (int k) 0               
  ff extend-ff (int k, int val, ff old-ff) =
       proc (int k1) if zero?(-(k1,k)) then val else (apply-ff old-ff k1)
  int apply-ff (ff f, int k) = (f k)
in let ff1 = (extend-ff 1 11 (extend-ff 2 22 (zero-ff)))
   in (apply-ff ff1 2)
")

;; error: apply-ff should be used by client
(type-check
"
lettype ff = (int -> int)
  ff zero-ff () = proc (int k) 0               
  ff extend-ff (int k, int val, ff old-ff) =
       proc (int k1) if zero?(-(k1,k)) then val else (old-ff k1)
  int apply-ff (ff f, int k) = (f k)
in let ff1 = (extend-ff 1 11 (extend-ff 2 22 (zero-ff)))
   in (ff1 2)
")


(type-check
"
lettype
  myint = int  % like the integers, but zero is represented as 1!
  myint zero() = 1
  myint succ(myint x) = add1(x)
  myint pred(myint x) = sub1(x)
  bool  iszero?(myint x) =  zero?(-(x,1))
in (succ (zero))
")

;; error:  succ should be used by client
(type-check
"
lettype
  myint = int  % like the integers, but zero is represented as 1!
  myint zero() = 1
  myint succ(myint x) = add1(x)
  myint pred(myint x) = sub1(x)
  bool  iszero?(myint x) =  zero?(-(x,1))
in add1((zero))
")

