; Symbolic derivation
(define (diff e) 
    (define (sum e1 e2) 
	(cond ((and (number? e1)
		      (number? e2))
		 (+ e1 e2))
	((eq? e1 0) e2)
	((eq? e2 0) e1)
	(else `(+ ,e1 ,e2))))
    (define (sub e1 e2) 
	(cond ((and (number? e1)
		       (number? e2)) 
		(- e1 e2))
	((eq? e1 0) `(* -1 ,e2))
	((eq? e2 0) e1)
	((eq? e1 e2) 0)
	(else `(-,e1 ,e2))))
    (define (prod e1 e2)
	(cond ((and (number? e1)
		      (number? e2))
		 (* e1 e2))
	((eq? e1 0) 0)
	((eq? e2 0) 0)
	((eq? e1 1) e2)
	((eq? e2 1) e1)
	(else `(* ,e1 ,e2))))
    (define (div e1 e2)
	(cond ((and (number? e1)
		      (number? e2))
		 (/ e1 e2))
	((eq? e1 0) 0)
	((eq? e2 1) e1)
	((eq? e1 e2) 1)
	(else `(/ ,e1 ,e2))))
    (define (expt* e1 e2)
	(cond ((eq? e2 0) 1)
		((eq? e2 1) e1)
		(else `(expt ,e1 ,e2))))
    (if (not (pair? e))
	(if (eq? e 'x) 1 0)
	(case (car e)
	((+) (let ((e1 (cadr e))
			(e2 (caddr e)))
		(sum (diff e1) (diff e2))))
	((-) (let ((e1 (cadr e))
			(e2 (caddr e)))
		(sub (diff e1) (diff e2))))
	((*) (let ((e1 (cadr e))
			(e2 (caddr e)))
		(sum (prod e1 (diff e2))
			(prod (diff e1) e2))))
	((/) (let ((z (cadr e))
			(n (caddr e)))
		(div (sub (prod n (diff z))
				(prod z (diff n)))
			(prod n n))))
	((expt) (let ((e1 (cadr e))
			(e2 (caddr e)))
		(if (number? e2)
		    (prod e2 (prod
			(expt* e1 (- e2 1))
			(diff e1)))
		    (error
		     "Not implemented"))))
	(else (error
		 "Invalid expression")))))
