Fun With Symbolic Derivatives in Lisp.

By Author: Josh Berry

Rather than just talk about the differences, lets have some fun. Recently, I linked someone the section on symbolic derivatives in lisp from the original SICP lectures.1

For brevity, I'm just going to quickly run through all of the functions the SICP defined. I keep the "playing/" prefix to keep from littering my current emacs session, and I obviously port the functions to elisp, from scheme.

First, the primitives used.

(defun playing/variable? (x) (symbolp x))
(defun playing/same-variable? (v1 v2) (and (playing/variable? v1) (playing/variable? v2) (eq v1 v2)))
(defun playing/make-sum (a1 a2) (list '+ a1 a2))
(defun playing/sum? (x) (and (listp x) (eq (car x) '+)))
(defun playing/addend (s) (cadr s))
(defun playing/augend (s) (caddr s))
(defun playing/make-product (m1 m2) (list '* m1 m2))
(defun playing/product? (x) (and (listp x) (eq (car x) '*)))
(defun playing/multiplier (p) (cadr p))
(defun playing/multiplicand (p) (caddr p))

Then, the derivative function.

(defun playing/deriv (exp var) (cond ((numberp exp) 0) ((playing/variable? exp) (if (playing/same-variable? exp var) 1 0)) ((playing/sum? exp) (playing/make-sum (playing/deriv (playing/addend exp) var) (playing/deriv (playing/augend exp) var))) ((playing/product? exp) (playing/make-sum (playing/make-product (playing/multiplier exp) (playing/deriv (playing/multiplicand exp) var)) (playing/make-product (playing/deriv (playing/multiplier exp) var) (playing/multiplicand exp)))) (t (error "unknown expression type -- DERIV" exp))))

Now, lets see if it works.

(playing/deriv playing/body 'x)
(+ (+ (* x 0) (* 1 2)) 0)

Not at all reduced form. And, for fun, the SICP section goes over how to fix this at a first order. So, lets quickly see that here.

(defun playing/make-sum (a1 a2) (cond ((playing/=number? a1 0) a2) ((playing/=number? a2 0) a1) ((and (numberp a1) (numberp a2)) (+ a1 a2)) (t (list '+ a1 a2))))
(defun playing/make-product (m1 m2) (cond ((or (playing/=number? m1 0) (playing/=number? m2 0)) 0) ((playing/=number? m1 1) m2) ((playing/=number? m2 1) m1) ((and (numberp m1) (numberp m2)) (* m1 m2)) (t (list '* m1 m2))))
(defun playing/=number? (exp num) (and (numberp exp) (= exp num)))

With that, lets try the deriv function one more time on the original. Showing the definition of "playing/body" to remind us what it was.

(playing/deriv playing/body 'x)

In case you forgot what the original was, here it is again.

(+ (* x 2) 12)