UNB/ CS/ David Bremner/ teaching/ cs4613/ tutorials/ tutorial11/ skeleton.rkt
#lang plait
(define-type Exp
  [numE  (val : Number)]
  [plusE  (l : Exp) (r : Exp)]
  [varE   (name : Symbol)]
  [let1E (id : Symbol) (named-expr : Exp) (bound-body : Exp)]
  [lamE  (param : Symbol) (body : Exp)]
  [appE (fun : Exp) (val : Exp)])

(define (bound name env)
  (if (none? (hash-ref env name)) #f #t))

(define (extend name env)
  (hash-set env name #t))

(define empty-env (hash empty))

(test (bound 'x empty-env) #f)
(test (bound 'x (extend 'y (extend 'x empty-env))) #t)

(define (union the-set other-set)
  (hash (map (lambda (x) (pair x #t))
             (append (hash-keys the-set) (hash-keys other-set)))))

(define (free-vars expr env)
  (type-case Exp expr
    [(numE n) empty-env]
    [(plusE l r) (union (free-vars l env) (free-vars r env))]
    [(let1E bound-id named-expr bound-body) ....]
    [(varE name) (if (bound name env) empty-env (extend name empty-env))]
    [(lamE bound-id bound-body) ....]
    [(appE fun-expr arg-expr) ....]))

(test (free-vars (numE 3) empty-env) empty-env)
(test (free-vars (plusE (varE 'x) (numE 3)) empty-env)
      (extend 'x empty-env))
(test (free-vars (plusE (varE 'x) (numE 3))
                 (extend 'x empty-env)) empty-env)
(test (free-vars (let1E 'x (numE 3) (plusE (varE 'x) (numE 3)))
                 empty-env) empty-env)
(test (free-vars (let1E 'x (numE 3) (plusE (varE 'x) (numE 3)))
                 (extend 'x empty-env)) empty-env)
(test (free-vars (let1E 'x (varE 'y) (plusE (varE 'x) (numE 3)))
                 (extend 'x empty-env)) (extend 'y empty-env))
(test (free-vars (lamE 'x  (plusE (varE 'x) (numE 3)))
                 (extend 'x empty-env)) empty-env)
(test (free-vars (appE (varE 'x) (varE 'x)) empty-env)
      (extend 'x empty-env))

(define-syntax nand
  (syntax-rules () [(_ arg ...)  ....]))

(test (nand #f) #t)
(test (nand #t (begin (/ 1 0) #t)) #f)
(test (nand #f #t (eq? (/ 1 0) 0)) #f)