UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture02/ calc.rkt
#lang plait
(define-type Exp
  [numE (n : Number)]
  [boolE (b : Boolean)]
  [plusE (left : Exp) (right : Exp)]
  [timesE (left : Exp) (right : Exp)]
  [cndE (test : Exp) (then : Exp) (else : Exp)])

(define-type Value
  [numV (the-number : Number)]
  [boolV (the-boolean : Boolean)])

(define (num-op op expr1 expr2)
  (local [(define (unwrap v)
            (type-case Value v
              [(numV n) n]
              [else (error 'num-op "NaN")]))]
    (numV (op (unwrap expr1)
              (unwrap expr2)))))

(define (boolean-decision v)
  (type-case Value v
    [(boolV b) b]
    [else (error 'if "not a boolean")]))

(define (calc e)
  (type-case Exp e
    [(numE n) (numV n)]
    [(boolE b) (boolV b)]
    [(plusE l r) (num-op + (calc l) (calc r))]
    [(timesE l r) (num-op * (calc l) (calc r))]
    [(cndE c t e) (if (boolean-decision (calc c))
                      (calc t)
                      (calc e))]))

(test (calc (plusE (numE 3) (numE 4))) (numV 7))
(test (calc (cndE (boolE #t) (numE 0) (numE 1)))
      (numV 0))