; symbolic maths package, including differentiation

(new (caddr s) (car (cddr s)))

(new (commute op a b)
	(if (number a)
		(list op a b)
		(list op b a)
	)
)

(new (power a b)
	(if
		(= a 1) 1
		(= b 0) 1 
		(= b 1) a
		(list '^ a b)
	)
)

(new (times a b)
	(if 
		(= a 0) 0 (= b 0) 0
		(= a 1) b (= b 1) a
		(and (number a) (number b)) (* a b)
		(equal a b) (power a 2)
		(commute '* a b)
	)
)

(new (plus a b)
	(if 
		(= a 0) b (= b 0) a
		(and (number a) (number b)) (+ a b)
		(equal a b) (times 2 a)
		(commute '+ a b)
	)
)

(new (sub a b)
	(if
		(= b 0) a
		(equal a b) 0
		(and (number a) (number b)) (- a b)
		(list '- a b)
	)
)

(new (div a b)
	(if 
		(= b 1) a
		(= a 0) 0
		(= a b) 1
		(and (number a) (number b)) (/ a b)
		(list '/ a b)
	)
)

(new (D x s)
	(if 
		(= x s) 1
		(= s 'u) 'du/dx
		(= s 'v) 'dv/dx
		(atom s) 0
		(let
			(seq ;(print 'D x 'of op a b)
			(if
				(= op '+) (plus (D x a) (D x b))
				(= op '-) (sub (D x a) (D x b))
				(= op '*) (plus (times a (D x b)) (times b (D x a)))
				(= op '/)
						(div (sub 
								(times b (D x a)) 
								(times a (D x b))) 
							(times b b)
						)
				(and (= op '^) (number b))
					(times (times b (D x a)) (power a (sub b 1))
					)
				'eh?
			))
			(op . (car s))
			(a . (cadr s))
			(b . (caddr s))
		)
	)
)

; default to differentiating wrt x, but permit (D var expr)
(new (Dx a)
	(if (not (cdr (from a))) (D 'x a)
		(D (car (from a)) (cadr (from a)))		
	)
)

(f 'xxxx '(+ t x))

(new (f s) (apply Dx (from s)))

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

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

(new (math s)
	(if
		(atom s) s
		(let
			(if
				(= op '+) (plus a b)
				(= op '-) (minus a b)
				(= op '*) (times a b)
				(= op '/) (div a b)
				(= op 'D) (apply Dx (cdr s))
				(list op 'not 'implemented)
			)
			(op . (car s))
			(a . (math (cadr s)))
			(b . (math (caddr s)))
		)
	)
)

(new symbolicmaths math) ; to make our Lecture notes exactly correct!

(math '(D x (+ 1 (+ x x))))
(D 'x '(/ (* 30 (* x x)) x)) 
(D 'x '(^ x 3))
(D 'x '(* x x)) 

(D 'x '(^ (* x a) 2))
(D 'x '(* x (+ x a)))
(D 'x '(* u v)) 

(language symbolicmaths) ; change to our new language

(* x x) 
(D x)  
(D y x)  
(D t (* 3 t))  
(D (+ 1 x))
(D (+ x (* 2 x))) 
(D (* x x))  
(D  x (* x x))  

(* x (+ x 2))
(+ x 2)
(* (+ x 2) x)
(* x x)
(* (+ x a) (+ x b))