Sweet Programs
Rewrite three programs from the playground using your sugar functions. The raw versions are shown in comments for reference.
Compare the two forms. The raw version of factorial:
["factorial", "=",
["lambda", "n", ["if", ["n", "==", 0], 1,
["n", "*", ["factorial", ["n", "-", 1]]]]]]
The sugared version:
define("factorial", fn("n",
iff(eq("n", 0), 1,
mul("n", call("factorial", sub("n", 1))))))
Same array. Same evaluation. But the second version reads almost like a sentence: “define factorial as a function of n; if n equals 0, then 1, else n times factorial of n minus 1.”
The brackets haven’t disappeared. JavaScript still uses parentheses for function calls. But every parenthesis has a name next to it that tells you what it means. That’s what sugar does: it replaces anonymous structure with named intent.
What You’ve Just Built
Syntactic sugar seems trivial. Twelve one-line functions. But it’s one of the most important ideas in programming language design.
Every language you use is layered with sugar. Python’s for x in list is sugar over iterator protocol calls. JavaScript’s async/await is sugar over promise chains. Even a + b is sugar. The language could make you write add(a, b), but + is shorter and familiar.
The evaluator doesn’t know or care whether you wrote [1, "+", 2] by hand or called add(1, 2). Sugar is invisible to the machine. It exists entirely for the human.
And that’s the point. Programs are read more often than they’re written. Making them easier to read, without changing what they mean, is never trivial.