Code

```#lang racket

;; This solution is partly taken from comments at
;; http://www.billthelizard.com/2012/04/sicp-256-258-symbolic-differentiation.html
;; It can be improved by extending simplifications

; df/dx, expression f, variable x
(define (deriv f x)
(cond ((number? f) 0)
((variable? f)
(if (same-variable? f x) 1 0))
((sum? f)
(make-sum (deriv (addend f) x)
(deriv (augend f) x)))
((product? f)
(make-sum
(make-product (multiplier f)
(deriv (multiplicand f) x))
(make-product (deriv (multiplier f) x)
(multiplicand f))))
((exponentiation? f) ; dn/dx = 0
(let ((u (base f))
(n (exponent f)))
(make-product (make-product
n
(make-exponentiation u (make-sum n -1)))
(deriv u x))))
(else
(error "unknown expression type -- DERIV" f))))

;; very clever thing
;; Return the operation on the LEVEL of expression ACCORDING to priorities
;; Parentheses are automatically out of the LEVEL!
(define (operation f)
(cond ((memq '+ f) '+)
((memq '* f) '*)
((memq '** f) '**)))

;; clever thing
;; returns all before op (operation)
;; this is a first argument of that operation
(define (prefix op f)
(define (iter f result)
(if (eq? (car f) op)
(reverse result)
(iter (cdr f) (cons (car f) result))))
(iter f '()))

;; returns all after op (operation)
;; this is a second argument of that operation
(define (postfix op f)
(cdr (memq op f)))

;; simple simplification
(define (simplify f)
(if (and (pair? f) (null? (cdr f)))
(simplify (car f))
f))

;; (first_arg op) procedure extracts first argument of the operation op in the expression f
;; (second_arg op) procedure extracts second argument of the operation op in the expression f
;; it is handy to combine first/second arg functions with simplification
(define (first-arg op) (lambda (f) (simplify (prefix op f))))
(define (second-arg op) (lambda (f) (simplify (postfix op f))))

;;; representing algebraic expressions

(define (variable? x) (symbol? x))

(define (same-variable? v1 v2)
(and (variable? v1) (variable? v2) (eq? v1 v2)))

(define (=number? exp num)
(and (number? exp) (= exp num)))

;; sum

(define (sum? x) (eq? '+ (operation x)))

(define (make-sum a1 a2)
(cond ((=number? a1 0) a2)
((=number? a2 0) a1)
((and (number? a1) (number? a2)) (+ a1 a2))
(else (list a1 '+ a2)))) ; order changed

(define addend (first-arg '+))

(define augend (second-arg '+))

;; product

(define (product? x) (eq? '* (operation x)))

(define (make-product m1 m2)
(cond ((or (=number? m1 0) (=number? m2 0)) 0)
((=number? m1 1) m2)
((=number? m2 1) m1)
((and (number? m1) (number? m2)) (* m1 m2))
(else (list m1 '* m2)))) ; order changed

(define multiplier (first-arg '*))

(define multiplicand (second-arg '*))

;; exponentiation

(define (exponentiation? x) (eq? '** (operation x)))

(define (make-exponentiation base exp)
(cond ((=number? exp 0) 1)
((=number? base 1) 1)
((=number? exp 1) base)
((and (number? base) (number? exp)) (expt base exp))
(else (list base '** exp))))

(define base (first-arg '**))

(define exponent (second-arg '**))

; tests

(operation '(x * x + 2))
(operation '((x + 1) ** 2 * x))
(operation '((x + 1) ** 2))

(newline)

(prefix
'*
'((x + 1) * (x * (y + 2))))

((first-arg '*)
'((x + 1) * (x * (y + 2))))

(postfix
'+
'(x * x + (y + 2)))

((second-arg '+)
'(x * x + (y + 2)))

(newline)

(simplify '((())))
(simplify '(((7))))
(simplify '(((x))))
(simplify '(((x + 1))))

(newline)

(deriv '(x + x + x) 'x)
(deriv '(x + x + x + x) 'x)
(deriv '(x * x * x) 'x)
(deriv '((x + 1) * x ** 2 * x) 'x)
(deriv '(x * (x + x) * x) 'x)
(deriv '(x + x * x) 'x)
(deriv '(x * x + x) 'x)
(deriv '((x + 2) * (x + 4)) 'x)
(deriv '(x * 3 + 5 * (x + y + 2)) 'x)
```

Output

```'+
'*
'**

'((x + 1))
'(x + 1)
'((y + 2))
'(y + 2)

'()
7
'x
'(x + 1)

3
4
'((x * (x + x)) + (x * x))
'(((x + 1) * ((x ** 2) + ((2 * x) * x))) + (x ** 2 * x))
'((x * ((x + x) + (2 * x))) + ((x + x) * x))
'(1 + (x + x))
'((x + x) + 1)
'((x + 2) + (x + 4))
8
```