Bene, non ce n'è davvero bisogno, se solo perché recur
non può assumere varargs (un recur
in cima alla funzione richiede un unico argomento finale definibile che raggruppa tutti gli argomenti passano l'ultimo argomento richiesto). Ciò non influisce sulla validità dell'esercizio, naturalmente.
Tuttavia, v'è un problema in quanto una "corretta" apply-recur
dovrebbe presumibilmente gestire seguenti del regolamento provvisorio argomenti restituiti da espressioni arbitrarie e non solo letterali:
;; 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))
Tuttavia, il valore di un'espressione arbitraria come (foo)
è semplicemente non disponibile, in generale, al momento dell'espansione della macro. (Probabilmente si assume che (vector 1 2 3)
abbia sempre lo stesso valore, ma foo
potrebbe significare cose diverse in momenti diversi (un motivo eval
non funzionerebbe), essere un let
locale piuttosto che un Var (un altro motivo eval
non funzionerebbe) etc.)
Così a dare una completamente generale apply-recur
, avremmo bisogno di essere in grado di determinare il numero di argomenti un regolare recur
modulo si aspetta e hanno (apply-recur some-expression)
espandere a qualcosa di simile
(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 finale nth
potrebbe essere necessario nthnext
se abbiamo a che fare con varargs, che presenta un problema simile a quanto descritto nel prossimo paragrafo. Inoltre, sarebbe una buona idea aggiungere un'affermazione di verificare la lunghezza del seqable restituito da some-expression
.)
Non sono a conoscenza di alcun metodo per determinare la corretta arity di un recur
in un punto particolare nel codice al momento della macro-espansione. Ciò non significa che non sia disponibile - è qualcosa che il compilatore deve sapere comunque, quindi forse c'è un modo per estrarre quell'informazione dai suoi interni. Anche così, qualsiasi metodo per farlo dovrebbe quasi certamente fare affidamento su dettagli di implementazione che potrebbero cambiare in futuro.
Quindi la conclusione è questa: anche se è possibile scrivere una tale macro (che potrebbe anche non essere il caso), è probabile che qualsiasi implementazione sarebbe molto fragile.
Come osservazione finale, crei un apply-recur
che sarebbe solo essere in grado di trattare letterali (in realtà la struttura generale della seq arg dovrebbe essere dato come letterale argomenti stessi - non necessariamente, quindi questo potrebbe funzionare: (apply-recur [foo bar baz])
=>(recur foo bar baz)
) sarebbe abbastanza semplice. Non sto rovinando l'esercizio dando via la soluzione, ma, come suggerimento, considera l'utilizzo di [email protected]
.
Certo, anche se ho preso la domanda per dire "dato che non si può semplicemente scrivere" (si applica ...), come si farebbe per scrivere una macro che catturerebbe il senso inteso di ciò. " –
Sì Michał, intendevo così. Grazie a entrambi. – JoeCamel