(defn diff [expr var] (cond (symbol? expr) (if (= expr var) 1 0) (number? expr) 0 (match expr [op & args] (case op '+ ['+ ;(map |(diff $ var) args)] '* (let [[a b] args] ['+ ['* (diff a var) b] ['* a (diff b var)]]) (errorf "unknown op: %v" op))))) (defn simplify [expr] (cond (symbol? expr) expr (number? expr) expr (match expr [op & args] (do (def args (map simplify args)) (case op '+ (do (def terms (filter |(not= $ 0) args)) (if (= (length terms) 1) (first terms) ['+ ;terms])) '* (cond (find |(= $ 0) args) 0 (find |(= $ 1) args) (first (filter |(not= $ 1) args)) ['* ;args]) # otherwise leave unchanged [op ;args]))))) (pp (simplify (diff '(+ (* x x) 3) 'x))) (pp (simplify (diff '(+ x 3) 'x)))