EDIT or E: type an expression in x EXAMPLE or N: cycle twelve worked examples up / down: scroll the worked solution Supported: + - * / ^, unary minus, parentheses, the variable x, the constants pi and e, and sin cos tan exp ln sqrt. Implicit multiplication works, so 2x, 3sin(x) and (x+1)(x-1) all parse. Case does not matter. Malformed input is named — UNBALANCED (, UNKNOWN FOO, BAD CHAR %, SYNTAX ERROR — rather than silently doing nothing.
A computer algebra system in Scratch: it parses an expression into a tree, differentiates it by rewriting the tree — product, quotient, power and chain rules — simplifies the result, prints it, shows the rule applied at every step, and plots f against f'. THE INTERESTING DECISION Nothing here evaluates f(x) in order to differentiate it. That is the whole distinction between a CAS and a calculator. The input becomes a tree of nodes, and the derivative is a different tree, built by structural rewriting: the node for u*v produces the node for u'v + uv', and no number is ever computed. Numbers appear exactly once, at the very end, when the plot samples the two finished trees to draw them. Two things made it fit in Scratch. No recursion — RPN is the traversal. goboscript's local variables are documented as undefined behaviour inside a recursive procedure, so the textbook recursive diff(node) is simply not available. It is not needed either: RPN is the post-order traversal of the tree, so one left-to-right walk over the RPN visits every node after both of its children. The walk carries two stacks — one of value nodes, one of derivative nodes — and each operator pops both operands' (value, derivative) pairs and pushes its own. That is the entire differentiator, iteratively, in a single pass. It also produces the steps in exactly the order a person would show the working: innermost first. Smart constructors instead of a simplify pass. mk(op, a, b) applies the algebraic identities at the moment a node is built. Because the walk is bottom-up, both children are already simplified when a parent is constructed, so one pass achieves what a separate fixed-point simplifier would — and every intermediate derivative in the worked solution comes out tidy without being simplified twice. What it folds: - two constants, in + - * / ^ (integer exponents up to 8) - x + 0, 0 + x, x - 0, x1, 1x, x/1 → x - x*0 → 0, 0/x → 0 - x^1 → x, x^0 → 1, 1^x → 1 - x - x → 0, x/x → 1 (possible only because of hash-consing, below) - x + x → 2x, xx → x^2 - -(-x) → x, -(c) → the negated constant - a + (-b) → a - b, a - (-b) → a + b, and the same for a negative constant on the right - signs hoisted out of products and quotients, so sin(x)*-sin(x) becomes -sin(x)^2 rather than being left as written — the hoist is what lets the "same factor twice" rule see through the negation in the first place - constants moved to the front of a product and out of its right factor, so the chain rule's cos(x^2)(2x) prints as 2cos(x^2)x - constants moved to the back of a sum, so 1 + x prints as x + 1 - ln(1), sin(0), tan(0), sqrt(0) → 0; exp(0), cos(0), sqrt(1) → 1. Only exact identities: sin(2) is more useful left symbolic than turned into 0.909297. node() is also hash-consed: every node is keyed by "op:a:b:val" and a lookup returns the existing index if there is one. item # of list is a single block, so that is cheap, and it buys three things at once. Identical subtrees are shared instead of duplicated; structural equality becomes an integer comparison, which is the only reason x - x → 0 and x/x → 1 are possible at all; and the tree stops growing exponentially on inputs like (x^2+1)/(x^2-1) where the same subexpression occurs four times. On sin(x)*cos(x) the status bar reports 12 nodes, 2 of them shared and 6 rewrites applied. All original - code, art and sound. See Inside is open.