; an approach for extending LISP with simple symbolic maths operators

(new (numeric+ a b) (+ a b))
(new (numeric- a b) (- a b))
(new (numeric* a b) (* a b))
(new (numeric/ a b) (/ a b))

; + and * commute, and we want to sort their parameters in order
; we put numbers first
; we keep a list of names, and names encountered later have higher name# numbers
; so we then sort on the name# number

(new names Ø)

(new (length s)
	(if
		(= Ø s) 0
		(+ 1 (length (cdr s)))
	)
)

(new (name# n)
	(if (number n) 0
		(member n names) (length (member n names))
		(length (set names (cons n names)))
	)
)

(new (swap a b)
	(> (name# a) (name# b))
)

(new (* a b)
	(if 
		(swap a b) (* b a)
		(= a 0) 0 
		(= a 1) b 
		(and (number a) (number b)) (numeric* a b)
		(list '* a b)
	)
)

(new (^ a b)
	(if
		(= a 1) 1
		(= b 1) a
		(= b 0) 1 
		(and (number b) (> b 0)) (* a (^ a (- b 1)))
		(and (number b) (< b 0)) (/ 1 (^ a (- 0 b)))
		(list '^ a b)
	)
)

(new (+ a b)
	(if 
		(swap a b) (+ b a)
		(= a 0) b 
		(and (number a) (number b)) (numeric+ a b)
		(equal a b) (* 2 a)
		(list '+ a b)
	)
)
(new (- a b)
	(if
		(= b 0) a
		(equal a b) 0
		(and (number a) (number b)) (numeric- a b)
		(list '- a b)
	)
)

(new (/ a b)
	(if 
		(= b 1) a
		(= a 0) 0
		(= a b) 1
		(= b 0) '∞
		(and (number a) (number b)) (numeric/ a b)
		(list '/ a b)
	)
)
; --------
; examples
; --------

(* 2 3)

(^ 2 5)

(/ 1 0)

(* (+ a 0) 2)

(^ a (* (- 2 1) y))

(- (+ b a) (* 1 (+ b a)))

(- (+ a b) (+ b a))

(+ a a)

; but it isn't perfect

(- (* 2 a) a)

(- (+ a a) a)

; this should be undefined, not infinity

(- (/ 1 0) (/ 1 0))