UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture4/ snippet-022.rkt
#lang plait
(define-type LAE
  [Num  (val : Number)]
  [Add  (l : LAE) (r : LAE)]
  [Sub  (l : LAE) (r : LAE)]
  [Mul  (l : LAE) (r : LAE)]
  [Div  (l : LAE) (r : LAE)]
  [Id   (name : Symbol)]
  [Let1 (name : Symbol)
        (val : LAE)
        (expr : LAE)])
; returns expr[to/from]. 
; leaves no free occurences of `to'
(define (subst expr from to) 
  (type-case LAE expr
    [(Num n) expr]
    [(Add l r) (Add (subst l from to) 
                    (subst r from to))]
    [(Sub l r) (Sub (subst l from to) 
		    (subst r from to))]
    [(Mul l r) (Mul (subst l from to) 
		    (subst r from to))]
    [(Div l r) (Div (subst l from to) 
		    (subst r from to))]
    [(Id name) (if (eq? name from) to expr)]
    [(Let1 bound-id named-expr bound-body)
     (if (eq? bound-id from)
       expr           ; <-- don't go in!
       (Let1 bound-id
             named-expr
             (subst bound-body from to)))]))

(test (subst
       ;; {+ x {let1 {x 3} x}
       (Add (Id 'x) (Let1 'x (Num 3) (Id 'x)))
       'x (Num 5))
      ;; {+ 5 {let1 {x 3} x}}
      (Add (Num 5) (Let1 'x (Num 3) (Id 'x))))
(test (subst
       ;; {+ x {let1 {y 3} x}}
       (Add (Id 'x) (Let1 'y (Num 3) (Id 'x)))
       'x (Num 5))
      ;; {+ 5 {let1 {y 3} 5}}
      (Add (Num 5) (Let1 'y (Num 3) (Num 5))))