💾 Archived View for stack.tilde.cafe › gemlog › 2022-07-08.anaphoric.gmi captured on 2023-09-28 at 16:15:33. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-09-08)

-=-=-=-=-=-=-

Common Lisp Anaphoric IF

gemini://tozip.chickenkiller.com/guile.gmi

The actual word is 'anaphoric', not 'anamorphic'!

TLDR:

(defmacro aif (test-form then-form &optional else-form)
  `(let ((it ,test-form))
     (if it ,then-form ,else-form)))

Anaphoric conditional constructs (usually implemented as macros in languages that have real macros, i.e. Lisps), allow us to test some condition, and refer to the result as 'it' within the rest of the expression.

The symbol it is secretly bound to the value of the conditional. This allows for very readable (and possibly more optimal) code, such as

(aif (some-complicated-numeric-expression-here) (1+ it) 0)

Anaphora has been questioned and ridiculed, largely for providing little help, and surprising the unsuspected user with the hidden 'it' variable. Without aif, the expression would be

(let ((it (some-complicated-expression-here)))
  (if it (1+ it) 0))

which is hardly worth a macro, an additional non-standard conditional, and possible confusion in the future.

However, the provided Guile (which is a Scheme) definition, seems absurdly verbose to me, a Common Lisp programmer. Common Lisp is built for macros while Scheme, a Lisp-1, has to go through hoops to make macros using a strange 'syntax' syntax. Because it's a Lisp-1, Scheme uses a single namespace for values and functions. Simple, Common Lisp-like macros, could create horrible problems with name collisions, so Scheme has an elaborate 'hygiene' for that, and Schemers often brag about that.

Common Lisp does not require such bolt-ons, and normal Common Lisp code can be used to manipulate Common Lisp expressions just as easily as any other data. On the occasions where unwanted symbols are injected into macros, GENSYM can create unique symbols easily.

Doug Hoyte writes on this subject in his classic book 'Let Over Lambda':

Like training wheels on a bicycle, hygiene systems are for the most part toys that should be discarded after even a modest level of skill has been acquired.

Here is another gem:

These solutions try to limit or eliminate the impact of unwanted variable capture but unfortunately do so at the expense of wanted, desirable variable capture…

Anaphora is exactly this case: the very much wanted _and_ desirable capture of the symbol 'it'. And so, the Common Lisp anaphoric if macro is defined simply as:

(defmacro aif (test-form then-form &optional else-form)
  `(let ((it ,test-form))
     (if it ,then-form ,else-form)))

This is a classic definition by Paul Graham from the book 'On Lisp', freely available here:

http://www.paulgraham.com/onlisptext.html

Even if you are not a lisper, you can see that the macro simply expands to the 'let' form above -- the ` constructs a let form which is returned, and the comma-prefixed expressions expand/substitute the provided parameters into the returned expression. This macro, in fact, wraps your code with a surrounding 'let' form, magically providing access to a new symbol 'it'.

I don't know enough Scheme to tell if the code from the original post is at all good. I occasionally feel the urge to learn it, but get really annoyed as the basic things I've grown used to are missing. But some very intelligent people I deeply respect love Scheme, so it can't be that bad...

I do love Common Lisp!

home

index