August 2018, rev. October 2018

When a new feature is added or a bug is fixed, it helps to make a pass and check how the change affects the design. Adding something small can lead to removing something big.

There's a small bug in Lisp that can remove something big in its design.

In SBCL, CLisp and Arc, running backquote-unquote-splice throws an exception. Backquote ` is often used to generate code in a macro. Unquote-splice ,@ inlines a list (unquotes a list) inside backquote:

(= a (list 2 3 4))
(list 1 `,@a 5) -> exception

I don't see why Lisp can't inline the list above and return (1 2 3 4 5).

Inlining at the top-level is different because there's nothing to splice the list onto. Backquote isn't nested inside another expression there. It's semantically invalid when inlining at the top-level to return multiple times, one per list element, but it may be ok to return only the last element of the list: 4.

`,@(list 2 3 4) -> ?

Fine, there's a small bug with `,@. Now what could this lead to?

I don't know the history to be sure, but I wonder if not fixing this bug of backquote-unquote-splice throwing an exception lead to keeping apply in Lisp. Apply is a built-in function that takes two parameters, a function and a list, and calls the function with the list elements as its parameters. Apply can pass parameters to a function when the number of parameters is unknown at compile time.

(= add (fn (a b) (+ a b)))
(= params (list 1 2))
(apply add params) -> 3

When the parameters are known at compile time, add can be expressed without apply:

(add 1 2) -> 3

So at compile time apply is unnecessary. But at runtime Lisp needed apply to pass an unknown number of parameters to the function.

Apply couldn't inline an unknown number of parameters at runtime when the first Lisp was written. Backquote and unquote-splice didn't exist then, because macros were added later to Lisp after apply.

After macros were added, was there a pass to check how they affect the design of apply?

If inlining parameters for apply was possible by (a) fixing this 50-year old bug and (b) generating code at runtime instead of read time, then apply would be unnecessary at runtime and it can be removed.

(apply add params) -> 3 ; unnecessary
(add `,@params) -> 3    ; possible

Generating code at runtime with `,@ can be slow because internally backquote calls eval. But there's a peephole optimization that can substitute apply when `,@ is used with a single element. If a Lisp internally always passes the parameters to a function as a list, then skip the `,@ and just pass the params; they're already a list. Apply is unnecessary outside the core.

If according to Wikipedia the eval-apply cycle is "the essence of evaluating Lisp" and apply can be removed, this changes half of the essence of evaluating Lisp. Evaluating Lisp may be less about apply and more about generating source code at runtime.