(defn ^:no-doc derivative
"Returns the symbolic derivative of the expression `expr`, which should
represent a function like `f`.
If the expression is already a derivative like `(D f)` or `((expt D 2) f)`,
`derivative` will increase the power of the exponent.
For example:
```clojure
(derivative 'f) ;;=> (D f)
(derivative '(D f)) ;;=> ((expt D 2) f)
(derivative '((expt D 2) f)) ;;=> ((expt D 3) f)
```"
[expr]
(cond (derivative? expr)
(let [f (first (operands expr))]
(list (expt g/derivative-symbol 2)
f))
(iterated-derivative? expr)
(let [pow (nth (operator expr) 2)
f (first (operands expr))]
(list (expt g/derivative-symbol (inc pow))
f))
:else
(list g/derivative-symbol expr)))