Bueno, realmente no hay necesidad de eso, si solo porque recur
no puede tomar varargs (un recur
en la parte superior de la función toma un único argumento seqable final agrupando todos los argumentos pasan el último argumento requerido). Esto no afecta la validez del ejercicio, por supuesto.
Sin embargo, existe el problema de que un "buen" apply-recur
presumiblemente debe manejar SEQs argumento devueltos por expresiones arbitrarias y no sólo literales:
;; this should work...
(apply-recur [1 2 3])
;; ...and this should have the same effect...
(apply-recur (vector 1 2 3))
;; ...as should this, if (foo) returns [1 2 3]
(apply-recur (foo))
Sin embargo, el valor de una expresión arbitraria como (foo)
es simplemente no disponible, en general, en el tiempo de expansión de macro. (Quizás se asuma que (vector 1 2 3)
siempre arroja el mismo valor, pero foo
puede significar cosas diferentes en momentos diferentes (una razón eval
no funcionaría), sea un let
- local de destino en lugar de un Var (otra razón eval
no funcionaría), etc.)
Así, para escribir totalmente en general apply-recur
, tendríamos que ser capaces de determinar cuántos argumentos esperaría una forma regular y tienen recur
(apply-recur some-expression)
expanda a algo así como
(let [seval# some-expression]
(recur (nth seval# 0)
(nth seval# 1)
...
(nth seval# n-1))) ; n-1 being the number of the final parameter
(La final nth
podría necesitar ser nthnext
si se trata de varargs, que presenta un problema similar al descrito en el párrafo siguiente. Además, sería una buena idea añadir una afirmación para comprobar la longitud de la seqable devuelto por some-expression
.)
No estoy al tanto de cualquier método para determinar la aridad apropiado de un recur
en un punto particular en el código en el tiempo de macro-expansión. Eso no significa que uno no esté disponible; eso es algo que el compilador necesita saber de todos modos, entonces quizás haya una forma de extraer esa información de sus partes internas. Aun así, cualquier método para hacer eso seguramente necesitaría confiar en los detalles de implementación que podrían cambiar en el futuro.
Por lo tanto, la conclusión es esta: incluso si es posible escribir tal macro (lo que podría no ser el caso), es probable que cualquier implementación sea muy frágil.
Como comentario final, escribiendo un apply-recur
que sólo sería capaz de hacer frente a los literales (en realidad tendría que ser dada como un literal de la estructura general de la SEC arg; los argumentos propios - no necesariamente, entonces esto podría funcionar: (apply-recur [foo bar baz])
=>(recur foo bar baz)
) sería bastante simple. No estoy arruinando el ejercicio regalando la solución, pero, como sugerencia, considere usar [email protected]
.
Claro, aunque tomé la pregunta en el sentido de "dado que uno no puede simplemente escribir" (aplicar recurrencia ...) ', ¿cómo se puede escribir una macro que capture el sentido intencionado de eso?" –
Sí Michał, lo dije en serio. Gracias a los dos. – JoeCamel