(module tests mzscheme
  
  (provide tests-for-run tests-for-check)
  ;;;;;;;;;;;;;;;; tests ;;;;;;;;;;;;;;;;
  
  (define tests-for-run
    '(
  
      ;; simple arithmetic
      (positive-const "11" 11)
      (negative-const "-33" -33)
      (simple-arith-1 "-(44,33)" 11)
  
      ;; nested arithmetic
      (nested-arith-left "-(-(44,33),22)" -11)
      (nested-arith-right "-(55, -(22,11))" 44)
  
      ;; simple variables
      (test-var-1 "x" 10)
      (test-var-2 "-(x,1)" 9)
      (test-var-3 "-(1,x)" -9)
      
      ;; simple unbound variables
      (test-unbound-var-1 "foo" error)
      (test-unbound-var-2 "-(x,foo)" error)
  
      ;; simple conditionals
      (if-true "if zero?(0) then 3 else 4" 3)
      (if-false "if zero?(1) then 3 else 4" 4)
      
      ;; test dynamic typechecking
      (no-bool-to-diff-1 "-(zero?(0),1)" error)
      (no-bool-to-diff-2 "-(1,zero?(0))" error)
      (no-int-to-if "if 1 then 2 else 3" error)

      ;; make sure that the test and both arms get evaluated
      ;; properly. 
      (if-eval-test-true "if zero?(-(11,11)) then 3 else 4" 3)
      (if-eval-test-false "if zero?(-(11, 12)) then 3 else 4" 4)
      
      ;; and make sure the other arm doesn't get evaluated.
      (if-eval-test-true-2 "if zero?(-(11, 11)) then 3 else foo" 3)
      (if-eval-test-false-2 "if zero?(-(11,12)) then foo else 4" 4)

      ;; simple let
      (simple-let-1 "let x = 3 in x" 3)

      ;; make sure the body and rhs get evaluated
      (eval-let-body "let x = 3 in -(x,1)" 2)
      (eval-let-rhs "let x = -(4,1) in -(x,1)" 2)

      ;; check nested let and shadowing
      (simple-nested-let "let x = 3 in let y = 4 in -(x,y)" -1)
      (check-shadowing-in-body "let x = 3 in let x = 4 in x" 4)
      (check-shadowing-in-rhs "let x = 3 in let x = -(x,1) in x" 2)

      ;; simple applications
      (apply-proc-in-rator-pos "(proc(int x) -(x,1)  30)" 29)
      (interp-ignores-type-info-in-proc "(proc((int -> int) x) -(x,1)  30)" 29)
      (apply-simple-proc "let f = proc (int x) -(x,1) in (f 30)" 29)
      (let-to-proc-1 "(proc((int -> int) f)(f 30)  proc(int x)-(x,1))" 29)


      (nested-procs "((proc (int x) proc (int y) -(x,y)  5) 6)" -1)
      (nested-procs2 "let f = proc(int x) proc (int y) -(x,y) in ((f -(10,5)) 6)"
        -1)
      
      (y-combinator-1 "
let fix =  proc (bool f)
            let d = proc (bool x) proc (bool z) ((f (x x)) z)
            in proc (bool n) ((f (d d)) n)
in let
    t4m = proc (bool f) proc(bool x) if zero?(x) then 0 else -((f -(x,1)),-4)
in let times4 = (fix t4m)
   in (times4 3)" 12)
      
      ;; simple letrecs
      (simple-letrec-1 "letrec int f(int x) = -(x,1) in (f 33)" 32)
      (simple-letrec-2
        "letrec int f(int x) = if zero?(x)  then 0 else -((f -(x,1)), -2) in (f 4)"
        8)

      (simple-letrec-3
        "let m = -5 
 in letrec int f(int x) = if zero?(x) then 0 else -((f -(x,1)), m) in (f 4)"
        20)
      
                                        ;      (fact-of-6  "letrec
                                        ;  fact(x) = if zero?(x) then 1 else *(x, (fact sub1(x)))
                                        ;in (fact 6)" 
                                        ;                  720)
      
      (HO-nested-letrecs
        "letrec int even((int -> int) odd)  = proc(int x) if zero?(x) then 1 else (odd -(x,1))
   in letrec  int odd(int x)  = if zero?(x) then 0 else ((even odd) -(x,1))
   in (odd 13)" 1)

       (modules-take-one-value
        "module m : {val u : int} = {val u = 3}
         from m take u"
        3)

       ;; the interpreter doesn't know about the abstraction boundaries.
       (modules-take-from-parameterized-module
        "module m (m1:{}) : {val u : int}  = {val u = 3}
         from m take u"
        error)

       (modules-check-interface-subtyping-1 "
         module m : {val u : int}  = {val u = 3 val v = 4}
         from m take u"
        3)

       (modules-take-one-value-but-interface-bad "
         module m : {}  = {val u = 3}
         from m take u"
        3)

       (modules-take-bad-value
        "module m : {}  = {val u = 3}
         from m take x"
        error)       

        (modules-two-vals
        "module m : {val u:int val v:int}  
                  = {val u = 44 val v = 33}
         -(from m take u, from m take v)"
        11)


        (modules-two-vals-bad-interface-1
        "module m : {val u : int val v : bool}  
                  = {val u = 44 val v = 33}
         -(from m take u, from m take v)"
        11)

        (modules-check-let*-1
        "module m : {val u : int val v : int}
                  = {val u = 44 val v = -(u,11)}
         -(from m take u, from m take v)"
        11)

      (modules-check-let*-2
        "module m1 : {val u : int} = {val u = 44}
         module m2 : {val v : int} = {val v = -(from m1 take u,11)}
         -(from m1 take u, from m2 take v)"
        11)

      (modules-export-abs-type-1
        "module m1 : {type t} = {type-abbrev t = int}
         33"
        33)

      (modules-take-from-ints-0.1
        "module m1
          : {type t  
             val zero:t} 
          = {type-abbrev t = int
             val zero = 0}
         33"
        33)


       (modules-take-from-ints-0.1.91
        "module m1
            : {type t
               val zero : t}
            = {type-abbrev t = int
               val zero = 0
               val foo = 3}
         let check = proc (from m1 take t  x) zero?(0)
         in (check  from m1 take zero)"
        #t)


       (modules-take-from-ints-0.2
        "module m1
          : {type t
             val zero:t
             val check : (t -> bool) } 
          = {type-abbrev t = int
             val zero = 0
             val check = proc(t x) zero?(x)}
         (from m1 take check  from m1 take zero)"
       #t)

      (modules-take-from-ints-1
        "module int1
          : {type t
             val zero:t
             val succ: (t -> t)
             val pred: (t -> t) 
             val check: (t -> bool) }
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val check = proc(t x) zero?(x) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let check = from int1 take check
         in (check (s (s (p (s z)))))"
        #f)

   (modules-take-from-ints-2
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> bool) } 
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        33)

   
   (modules-take-from-ints-2-bad-1
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> bool) } 
          = {val zero = proc (? x) x
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(0)
             }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        error)

   (modules-take-from-ints-3
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> int) } 
          = {val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        33)

   (modules-apply-param-module-0.1
       "module copy-module
         ( m : {type t 
                val zero:t })
         : {type t 
            val zero:t}
         = {type-abbrev t = from m take t
            val zero = from m take zero}
        33"
       33)

   (modules-myints-0.1 "
        module int1:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
         = {val zero = 0
            val succ = proc(? x) -(x,-2)
            val pred = proc(? x) -(x,2)
            val is-zero = proc (? x) zero?(x)
            }
         let zero = from int1 take zero
         in let succ = from int1 take succ
         in let is-zero = from int1 take is-zero
         in (succ (succ zero))"
     4)

   (modules-myints-0.2 "
        module int1:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
         = {val zero = 0
            val succ = proc(? x) -(x,2)
            val pred = proc(? x) -(x,-2)
            val is-zero = proc (? x) zero?(x)
            }
         let zero = from int1 take zero
         in let succ = from int1 take succ
         in let is-zero = from int1 take is-zero
         in (succ (succ zero))"
     -4)

    (modules-apply-param-module-1 "
        module makeints (m:{type t
                            val zero : (t -> t)
                            val succ : (t -> t)
                            val pred : (t -> t)
                            val is-zero : (t -> bool)})
                       : {type t
                          val zero : (t -> t)
                          val succ : (t -> t)
                          val pred : (t -> t)
                          val is-zero : (t -> bool)}
        = {val zero = from m take zero
           val succ = proc (? x) 
                       (from m take succ (from m take succ x))
           val pred = proc (? x) 
                       (from m take pred (from m take pred x))
           val is-zero = proc (? x) (from m take is-zero x)
          }
        module int1:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
        = {val zero = 0
           val succ = proc(? x) -(x,2)
           val pred = proc(? x) -(x,-2)
           val is-zero = proc (? x) zero?(x)
           }
        module int2:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
        = (makeints int1)
        (from int2 take succ 
         (from int2 take succ 
          from int2 take zero)) "
       -8)


  (modules-apply-param-module-2
       "module makeints
         ( m : {type t 
                val zero:t
                val succ:(t -> t)
                val pred:(t -> t)
                val is-zero:(t -> bool) })
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}
         = {type-abbrev t = from m take t
            val zero = from m take zero
            val succ = proc (? x) 
                        (from m take succ (from m take succ x))
            val pred = proc (? x) 
                        (from m take pred (from m take pred x))
            val is-zero = proc (? x) (from m take is-zero x)
           }
        module int1
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}  
         = {type-abbrev t = int
            val zero = 0
            val succ = proc(? x) -(x,2)
            val pred = proc(? x) -(x,-2)
            val is-zero = proc (? x) zero?(x)
            }
        module int2
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}  
         = (makeints int1)
        let check = proc (from int2 take t x) zero?(0)
        in (check 
             (from int2 take succ 
               (from int2 take succ from int2 take zero)))"
       #t)

     (modules-apply-param-module-3
       "
        module makeints (m:{type t
                            val zero : (t -> t)
                            val succ : (t -> t)
                            val pred : (t -> t)
                            val is-zero : (t -> bool)})
                       : {type t
                          val zero : (t -> t)
                          val succ : (t -> t)
                          val pred : (t -> t)
                          val is-zero : (t -> bool)}
        = {val zero = from m take zero
           val succ = proc (? x) 
                       (from m take succ (from m take succ x))
           val pred = proc (? x) 
                       (from m take pred (from m take pred x))
           val is-zero = proc (? x) (from m take is-zero x)
          }
        module int1:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
        = {type-abbrev t = int
            val zero = 0
            val succ = proc(? x) -(x,2)
            val pred = proc(? x) -(x,-2)
            val is-zero = proc (? x) zero?(x)
            }
        module int2:{type t
                     val zero : (t -> t)
                     val succ : (t -> t)
                     val pred : (t -> t)
                     val is-zero : (t -> bool)}  
        = (makeints int1)
        let zero = from int2 take zero
        in let succ = from int2 take succ
        in let pred = from int2 take pred
        in let is-zero = from int2 take is-zero
        in letrec ? to-int (? n)
                           = if (is-zero n)
                              then 0
                              else -( (to-int (pred n)), -1)
        in (to-int (succ (succ zero)))
         "
        2
       )




   (type-abbrev-0
     "module m1 : {type-abbrev t = int
                   val zero : t}
                = {type-abbrev t = int
                   val zero = 0}
      -(from m1 take zero,1)"
     -1)

   (type-abbrev-1 
     "module m1 
       : {type t
          val zero : t }
       = {type-abbrev t = int
          val zero = 0 }
      module m2 
       : {type-abbrev t = from m1 take t   % don't know
                                           % what's in m1!
          val one : t}
       = {type-abbrev t = int
          val one = 1}
     -(from m2 take one, from m1 take zero)
     "
     1)

  (type-abbrev-2
    "module m1 
      : {type-abbrev t = int
         val zero : t }
      = {type-abbrev t = int
         val zero = 0 }
     module m2 
      : {type-abbrev t = from m1 take t   % now known to be int.
         val one : t}
      = {type-abbrev t = int
         val one = 1 }
      -(from m2 take one, from m1 take zero)
     "
     1)

  ;; this example shows the need for substitution in types in a module
  ;; application.   This also means you need to have the bound
  ;; variable in type of a parameterized module.

  (diamond-1 "
     module maker1 (m : {type t val succ : (t -> t)})
                  : {type-abbrev t = from m take t 
                     val  double : (t -> t)
                     }
                   = {type-abbrev t = from m take t
                      val double = let s = from m take succ
                              in proc (? x) (s (s x))
                     }

     module m0 : {type t 
                  val succ : (t -> t)
                  val zero : t
                 }
               = {type-abbrev t = int
                  val succ = proc(?x)-(x,-1)
                  val zero = 0
                 }
     module m2 : {type-abbrev t = from m0 take t
                  val  double : (t -> t)
                 }
               = (maker1 m0)
     let check = proc (from m0 take t x) zero?(0)
     in (check
          (from m2 take double
           from m0 take zero))
     "
     #t)





      ))

  (define tests-for-check
    '(
      ;; tests from run-tests:
  
      ;; simple arithmetic
      (positive-const "11" int)
      (negative-const "-33" int)
      (simple-arith-1 "-(44,33)" int)
  
      ;; nested arithmetic
      (nested-arith-left "-(-(44,33),22)" int)
      (nested-arith-right "-(55, -(22,11))" int)
  
      ;; simple variables
      (test-var-1 "x" int)
      (test-var-2 "-(x,1)" int)
      (test-var-3 "-(1,x)" int)

      (zero-test-1 "zero?(-(3,2))" bool)
      (zero-test-2 "-(2,zero?(0))" error)
      
      ;; simple unbound variables
      (test-unbound-var-1 "foo" error)
      (test-unbound-var-2 "-(x,foo)" error)
  
      ;; simple conditionals
      (if-true "if zero?(1) then 3 else 4" int)
      (if-false "if zero?(0) then 3 else 4" int)

      ;; make sure that the test and both arms get evaluated
      ;; properly. 
      (if-eval-test-true "if zero?(-(11,12)) then 3 else 4" int)
      (if-eval-test-false "if zero?(-(11, 11)) then 3 else 4" int)
      (if-eval-then "if zero?(1) then -(22,1) else -(22,2)" int)
      (if-eval-else "if zero?(0) then -(22,1) else -(22,2)" int)
      
      ;; make sure types of arms agree (new for lang5-1)
      
      (if-compare-arms "if zero?(0) then 1 else zero?(1)" error)
      (if-check-test-is-boolean "if 1 then 11 else 12" error)

      ;; simple let
      (simple-let-1 "let x = 3 in x" int)

      ;; make sure the body and rhs get evaluated
      (eval-let-body "let x = 3 in -(x,1)" int)
      (eval-let-rhs "let x = -(4,1) in -(x,1)" int)

      ;; check nested let and shadowing
      (simple-nested-let "let x = 3 in let y = 4 in -(x,y)" int)
      (check-shadowing-in-body "let x = 3 in let x = 4 in x" int)
      (check-shadowing-in-rhs "let x = 3 in let x = -(x,1) in x" int)

      ;; simple applications
      (apply-proc-in-rator-pos "(proc(int x) -(x,1)  30)" int)
      (checker-doesnt-ignore-type-info-in-proc 
        "(proc((int -> int) x) -(x,1)  30)"
        error) 
      (apply-simple-proc "let f = proc (int x) -(x,1) in (f 30)" int)
      (let-to-proc-1 "(proc( (int -> int) f)(f 30)  proc(int x)-(x,1))" int)


      (nested-procs "((proc (int x) proc (int y) -(x,y)  5) 6)" int)
      (nested-procs2
        "let f = proc (int x) proc (int y) -(x,y) in ((f -(10,5)) 3)"
        int)
      
      ;; simple letrecs
      (simple-letrec-1 "letrec int f(int x) = -(x,1) in (f 33)" int)
      (simple-letrec-2
        "letrec int f(int x) = if zero?(x) then 0 else -((f -(x,1)), -2) in (f 4)"
        int)

      (simple-letrec-3
        "let m = -5 
 in letrec int f(int x) = if zero?(x) then -((f -(x,1)), m) else 0 in (f 4)"
        int)

      (double-it "
letrec int double (int n) = if zero?(n) then 0 
                                  else -( (double -(n,1)), -2)
in (double 3)"
        int)

      ;; tests of expressions that produce procedures

      (build-a-proc-typed "proc (int x) -(x,1)" (int -> int))

      (build-a-proc-typed-2 "proc (int x) zero?(-(x,1))" (int -> bool))
      
      (bind-a-proc-typed
        "let f = proc (int x) -(x,1) in (f 4)"
        int) 

      (bind-a-proc-return-proc
        "let f = proc (int x) -(x,1) in f"
        (int -> int))

      (type-a-ho-proc-1
        "proc((int -> bool) f) (f 3)"
        ((int  -> bool) -> bool))

      (type-a-ho-proc-2
        "proc((bool -> bool) f) (f 3)"
        error)

      (apply-a-ho-proc
        "proc (int x) proc ( (int -> bool) f) (f x)"
        (int -> ((int -> bool) -> bool)))

      (apply-a-ho-proc-2
        "proc (int x) proc ( (int -> (int -> bool)) f) (f x)"
        (int -> ((int -> (int -> bool)) -> (int -> bool))) )

      (apply-a-ho-proc-3
        "proc (int x) proc ( (int -> (int -> bool)) f) (f zero?(x))"
	error)

      (apply-curried-proc
        "((proc(int x) proc (int y)-(x,y)  4) 3)"
        int)

      (apply-a-proc-2-typed
        "(proc (int x) -(x,1) 4)" 
        int)

      (apply-a-letrec "
letrec int f(int x) = -(x,1)
in (f 40)"
        int)

      (letrec-non-shadowing
        "(proc (int x)
      letrec bool loop(bool x) =(loop x)
       in x
     1)"
        int)


      (letrec-return-fact "
let times = proc (int x) proc (int y) -(x,y)    % not really times
in letrec 
     int fact(int x) = if zero?(x) then 1 else ((times x) (fact -(x,1)))
   in fact"
        (int -> int))

      (letrec-apply-fact "
let times = proc (int x) proc (int y) -(x,y)    % not really times
in letrec 
     int fact(int x) = if zero?(x) then 1 else ((times x) (fact -(x,1)))
   in (fact 4)"
        int)

      (pgm7b "
letrec 
  ? fact (? x) = if zero?(x) then 1 else -(x, (fact -(x,1)))
in fact"
        (int -> int))


      (dont-infer-circular-type 
        "letrec ? f (? x) = (f f) in 33"
        error)

      (polymorphic-type-1 
        "letrec ? f (? x) = (f x) in f"
        (tvar01 -> tvar02))

      ;; this test should fail, because the type given is insufficiently
      ;; polymorphic.  So we use it for testing the test harness, but not for
      ;; testing the checker.

      ;;       (polymorphic-type-1a
      ;;         "letrec ? f (? x) = (f x) in f"
      ;;         (tvar01 -> tvar01))

      (polymorphic-type-2 
        "letrec ?f (? x) = (f x) in proc (? n) (f -(n,1))"
        (int -> tvar01))

       (modules-take-one-value
        "module m : {val u : int} = {val u = 3}
         from m take u"
        int)

       (modules-take-from-parameterized-module
        "module m (m1:{}) : {val u : int}  = {val u = 3}
         from m take u"
        error)

       (modules-check-interface-subtyping-1 "
         module m : {val u : int} = {val u = 3 val v = 4}
         from m take u"
        int)


       (modules-take-one-value-but-interface-bad "
         module m : {}  = {val u = 3}
         from m take u"
        error)

       (modules-take-bad-value
        "module m : {}  = {val u = 3}
         from m take x"
        error)       

        (modules-two-vals
        "module m : {val u:int val v:int}  
                  = {val u = 44 val v = 33}
         -(from m take u, from m take v)"
        int)


        (modules-two-vals-bad-interface-1
        "module m : {val u : int val v : bool}  
                  = {val u = 44 val v = 33}
         -(from m take u, from m take v)"
        error)

       (modules-two-vals-bad-interface-2
        "module m:{val u:int val v:bool}  = {val v = zero?(0) val u = 33}
         -(from m take u, from m take v)"
        error)


        (modules-check-let*-1
        "module m : {val u : int val v : int}
                  = {val u = 44 val v = -(u,11)}
         -(from m take u, from m take v)"
        int)

      (modules-check-let*-2
        "module m1 : {val u : int} = {val u = 44}
         module m2 : {val v : int} = {val v = -(from m1 take u,11)}
         -(from m1 take u, from m2 take v)"
        int)

      (modules-export-abs-type-1
        "module m1 : {type t} = {type-abbrev t = int}
         33"
        int)

      (modules-take-from-ints-0.1
        "module m1
          : {type t  
             val zero:t} 
          = {type-abbrev t = int
             val zero = 0}
         33"
        int)


       (modules-take-from-ints-0.1.91
        "module m1
            : {type t
               val zero:t}
            = {type-abbrev t = int
               val zero = 0
               val foo = 3}
         let check = proc (from m1 take t  x) zero?(0)
         in (check  from m1 take zero)"
        bool)


       (modules-take-from-ints-0.2
        "module m1
          : {type t
             val zero:t
             val check : (t -> bool) } 
          = {type-abbrev t = int
             val zero = 0
             val check = proc(t x) zero?(x)}
         (from m1 take check  from m1 take zero)"
        bool)

       (modules-mybool-1
        "module mybool 
          : {type t
             val true : t
             val false : t
             val and : (t -> (t -> t))
             val not : (t -> t)
             val to-bool : (t -> bool)}
          = {type-abbrev t = int
             val true = 0
             val false = 1
             val and = proc (t x) proc (t y)
                        if zero?(x) then y else false
             val not = proc (t x) if zero?(x) then false else true
             val to-bool = proc (t x) 
                            if zero?(x) then zero?(0) else zero?(1)
             }
          (from mybool take to-bool  
           from mybool take false)
          "
         bool)

      (modules-take-from-ints-1
        "module int1
          : {type t
             val zero:t
             val succ: (t -> t)
             val pred: (t -> t) 
             val check: (t -> bool) }
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val check = proc(t x) zero?(0) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let check = from int1 take check
         in (check (s (s (p (s z)))))"
        bool)

   (modules-take-from-ints-2
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> bool) } 
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        int )

   
   (modules-take-from-ints-2-bad-1
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> bool) } 
          = {val zero = proc (? x) x
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x)
             }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        error)

   (modules-take-from-ints-3
        "module int1
          : {type t
             val zero: t
             val succ: (t -> t)
             val pred: (t -> t)
             val is-zero : (t -> int) } 
          = {val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
         let z = from int1 take zero
         in let s = from int1 take succ
         in let p = from int1 take pred
         in let z? = from int1 take is-zero
         in if (z? (s z)) then 22 else 33"
        error)

   (modules-check-shadowing-1 "
      module int1:{type t
                   val zero : t
                   val succ : (t -> t)
                   val is-zero : (t -> bool)} 
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
      module int2 : {val zero : from int1 take t
                     val succ : (from int1 take t -> from int1 take t)
                     val is-zero : (from int1 take t -> bool)}
                  = {val zero = from int1 take zero
                     val succ = from int1 take succ
                     val is-zero = from int1 take is-zero}
      let s = from int2 take succ
      in let z? = from int2 take is-zero
      in let z = from int2 take zero
      in (z? (s z))"
     bool)

   (modules-check-shadowing-1.8
     "module int1 : {type t  val zero : t} 
                  = {type-abbrev t = int val zero = 0}
      module int2 : {val foo : from int1 take t}
                  = {val foo = from int1 take zero}
      let v = from int2 take foo
      in 33
     " int)

   (modules-check-shadowing-1.9 
     "module int1 : {type t  val zero : t} 
                  = {type-abbrev t = int val zero = 0}
      module int1 : {val foo : from int1 take t}
                  = {val foo = from int1 take zero}
      let v = from int1 take foo
      in 33
     " int)

   (modules-check-shadowing-2 "
      module int1:{type t
                   val zero : t
                   val succ : (t -> t)
                   val is-zero : (t -> bool)} 
          = {type-abbrev t = int
             val zero = 0
             val succ = proc(? x) -(x,-1)
             val pred = proc(? x) -(x,1)
             val is-zero = proc (? x) zero?(x) }
      module int1 : {val zeroz : from int1 take t
                     val succ : (from int1 take t -> from int1 take t)
                     val is-zero : (from int1 take t -> bool)}
                  = {val zeroz = from int1 take zero
                     val succ = from int1 take succ
                     val is-zero = from int1 take is-zero}
      let s = from int1 take succ
      in let z? = from int1 take is-zero
      in let z = from int1 take zeroz
      in (z? (s z))"
     bool)

   (modules-apply-param-module-0.1
       "module copy-module
         ( m : {type t 
                val zero:t })
         : {type t 
            val zero:t}
         = {type-abbrev t = from m take t
            val zero = from m take zero}
        33"
       int)



     (modules-add-double-1
       "module add-double (m:{type t 
                        val zero : t 
                        val succ : (t -> t)
                        val pred : (t -> t)
                        val is-zero : (t -> bool)})
         : {val double : (from m take t -> from m take t)}
         = {val double = letrec from m take t 
                          double (from m take t x) =
                          if (from m take is-zero x)
                           then from m take zero
                           else (from m take succ
                                 (from m take succ x))
                         in double}
        module int1
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}  
         = {type-abbrev t = int
            val zero = 0
            val succ = proc(? x) -(x,2)
            val pred = proc(? x) -(x,-2)
            val is-zero = proc (? x) zero?(x)
            }  
        module int2 
         : {val double : (from int1 take t -> from int1 take t) }
         = (add-double int1)
        (from int1 take is-zero
          (from int2 take double
            (from int1 take succ
              from int1 take zero)))"
       bool)

  (modules-apply-param-module-1
       "module makeints
         ( m : {type t 
                val zero:t
                val succ:(t -> t)
                val pred:(t -> t)
                val is-zero:(t -> bool) })
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}
         = {type-abbrev t = from m take t
            val zero = from m take zero
            val succ = proc (? x) 
                        (from m take succ (from m take succ x))
            val pred = proc (? x) 
                        (from m take pred (from m take pred x))
            val is-zero = proc (? x) (from m take is-zero x)
           }
        module int1
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}  
         = {type-abbrev t = int
            val zero = 0
            val succ = proc(? x) -(x,2)
            val pred = proc(? x) -(x,-2)
            val is-zero = proc (? x) zero?(x)
            }
        module int2
         : {type t 
            val zero:t
            val succ:(t -> t)
            val pred:(t -> t)
            val is-zero:(t -> bool)}  
         = (makeints int1)
        let check = proc (from int2 take t x) zero?(0)
        in (check 
             (from int2 take succ 
               (from int2 take succ from int2 take zero)))"
       bool)

   (type-abbrev-0
     "module m1 : {type-abbrev t = int
                   val zero : t}
                = {type-abbrev t = int
                   val zero = 0}
      -(from m1 take zero,1)"
     int)

   (type-abbrev-1 
     "module m1 
       : {type t
          val zero : t }
       = {type-abbrev t = int
          val zero = 0 }
      module m2 
       : {type-abbrev t = from m1 take t   % don't know
                                           % what's in m1!
          val one : t}
       = {type-abbrev t = int
          val one = 1}
     -(from m2 take one, from m1 take zero)
     "
     error)

  (type-abbrev-2
    "module m1 
      : {type-abbrev t = int
         val zero : t }
      = {type-abbrev t = int
         val zero = 0 }
     module m2 
      : {type-abbrev t = from m1 take t   % now known to be int.
         val one : t}
      = {type-abbrev t = int
         val one = 1 }
      -(from m2 take one, from m1 take zero)
     "
     int)

  ;; this example shows the need for substitution in types in a module
  ;; application.   This also means you need to have the bound
  ;; variable in type of a parameterized module.

  (diamond-1 "
     module maker1 (m : {type t val succ : (t -> t)})
                  : {type-abbrev t = from m take t 
                     val  double : (t -> t)
                     }
                   = {type-abbrev t = from m take t
                      val double = let s = from m take succ
                              in proc (? x) (s (s x))
                     }

     module m0 : {type t 
                  val succ : (t -> t)
                  val zero : t
                 }
               = {type-abbrev t = int
                  val succ = proc(?x)-(x,-1)
                  val zero = 0
                 }
     module m2 : {type-abbrev t = from m0 take t
                  val  double : (t -> t)
                 }
               = (maker1 m0)
     let check = proc (from m0 take t x) zero?(0)
     in (check
          (from m2 take double
           from m0 take zero))
     "
     bool)
    

      ))
  )