I got this idea from XKCD's Hofstadter comic; what's the best way to create a conditional loop in (any) Lisp dialect that executes a function until it returns NIL
at which time it collects the returned values into a list.
For those who haven't seen the joke, it's goes that Douglas Hofstadter's “eight-word” autobiography consists of only six words: “I'm So Meta, Even This Acronym” containing continuation of the joke: (some odd meta-paraprosdokian?) “Is Meta” — the joke being that the autobiography is actually “I'm So Meta, Even This Acronym Is Meta”. But why not go deeper?
Assume the acronymizing function META
that creates an acronym from a string and splits it into words, returns NIL
if the string contains but one word:
(meta "I'm So Meta, Even This Acronym") ⇒ "Is Meta"
(meta (meta "I'm So Meta, Even This Acronym")) ⇒ "Im"
(meta (meta (meta "I'm So Meta, Even This Acronym"))) ⇒ NIL
(meta "GNU is Not UNIX") ⇒ "GNU"
(meta (meta "GNU is Not UNIX")) ⇒ NIL
Now I'm looking for how to implement a function so that:
(so-function #'meta "I'm So Meta, Even This Acronym")
⇒ ("I'm So Meta, Even This Acronym" "Is Meta" "Im")
(so-function #'meta "GNU is Not Unix")
⇒ ("GNU is Not Unix" "GNU")
What's the best way of doing this?
This is easy. I don't want to write a solution, so instead I will -- but it'll be the crappy elisp version, which might lead to unexpected enlightenment if you'll follow through:
To try this out you'll need that
meta
, but I don't know how you'd decide where to put the spaces, so instead I'll fake it:This makes the code that you want work. As for the enlightenment -- try to write it so instead of what you want,
so-function
will be a higher order function -- one that will work like this:or, in Scheme:
The big hint here is that you can't do it in plain elisp (at least not without tricks from the
cl
library). To get full credit, avoid the mutations -- this will lead to the natural way you'd write it in Scheme, and might even look more readable than thesetq
version.Threw this together and it seems to work:
Using a slightly modified version of the
meta
Eli Barzilay posted,I get the result you were looking for.
Edit: @Rainer Joswig pointed out that
collect-until-null
will exhaust the stack if given a sufficiently large sequence. Below is Rainer's iterative version without this problem.