I’m not very familiar with Clojure/Lisp macros. I would like to write apply-recur macro which would have same meaning as (apply recur ...)
I guess there is no real need for such macro but I think it’s a good exercise. So I’m asking for your solution.
Well, there really is no need for that, if only because
recurcannot take varargs (arecurto the top of the function takes a single final seqable argument grouping all arguments pass the last required argument). This doesn’t affect the validity of the exercise, of course.However, there is a problem in that a “proper”
apply-recurshould presumably handle argument seqs returned by arbitrary expressions and not only literals:However, the value of an arbitrary expression such as
(foo)is simply not available, in general, at macro expansion time. (Perhaps(vector 1 2 3)might be assumed to always yield the same value, butfoomight mean different things at different times (one reasonevalwouldn’t work), be alet-bound local rather than a Var (another reasonevalwouldn’t work) etc.)Thus to write a fully general
apply-recur, we would need to be able to determine how many arguments a regularrecurform would expect and have(apply-recur some-expression)expand to something like(The final
nthmight need to benthnextif we’re dealing with varargs, which presents a problem similar to what is described in the next paragraph. Also, it would be a good idea to add an assertion to check the length of the seqable returned bysome-expression.)I am not aware of any method to determine the proper arity of a
recurat a particular spot in the code at macro-expansion time. That does not mean one isn’t available — that’s something the compiler needs to know anyway, so perhaps there is a way to extract that information from its internals. Even so, any method for doing that would almost certainly need to rely on implementation details which might change in the future.Thus the conclusion is this: even if it is at all possible to write such a macro (which might not even be the case), it is likely that any implementation would be very fragile.
As a final remark, writing an
apply-recurwhich would only be capable of dealing with literals (actually the general structure of the arg seq would need to be given as a literal; the arguments themselves — not necessarily, so this could work:(apply-recur [foo bar baz])=>(recur foo bar baz)) would be fairly simple. I’m not spoiling the exercise by giving away the solution, but, as a hint, consider using~@.