#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))