Emacs 24 ha aggiunto associazioni binarie opzionali per le variabili locali. Vorrei utilizzare questa funzionalità nel mio modulo, pur mantenendo la compatibilità con XEmacs e le precedenti versioni di Emacs.Ambito lessicale in Emacs: compatibilità con la versione precedente di Emacsen
Prima di Emacs 24, il modo più semplice per ottenere chiusure era utilizzando il modulo lexical-let
definito in cl-macs
, che emulava lo scope lessicale con alcuni intelligenti trucchi della macro. Anche se questo non è mai stato molto popolare tra i programmatori elisp, ha fatto il lavoro, la creazione di chiusure reali ed efficienti, a patto che vi siete ricordati di metterli in lexical-let
, come in questo pseudocodice:
(defun foo-open-tag (tag data)
"Maybe open TAG and return a function that closes it."
... do the work here, initializing state ...
;; return a closure that explicitly captures internal state
(lexical-let ((var1 var1) (var2 var2) ...)
(lambda()
... use the captured vars without exposing them to the caller ...
)))
La domanda è: qual è la modo migliore per utilizzare i nuovi collegamenti lessicali, pur mantenendo il supporto per Emacs 23 e per XEmacs? Attualmente ho risolto definendo una macro-specific pacchetto che si espande in lexical-let
o in azioni ordinarie let
seconda che lexical-binding
è legato e vero:
(defmacro foo-lexlet (&rest letforms)
(if (and (boundp 'lexical-binding)
lexical-binding)
`(let ,@letforms)
`(lexical-let ,@letforms)))
(put 'foo-lexlet 'lisp-indent-function 1)
... at the end of file, turn on lexical binding if available:
;; Local Variables:
;; lexical-binding: t
;; End:
Questa soluzione funziona, ma ci si sente goffo perché la nuova forma speciale è non -standard, non evidenzia in modo corretto, non può essere calpestato sotto edebug
e generalmente attira l'attenzione su se stesso. C'è un modo migliore?
EDIT
Due esempi di idee per più intelligenti soluzioni (non necessariamente buono) che permettono il codice di continuare a utilizzare moduli standard per creare dispositivi di chiusura
uso di un consiglio o una macro del compilatore per rendere
lexical-let
espandibile alet
sottolexical-bindings
se illexical-let
assegna solo ai simboli che sono lessicamente scoped comunque. Questo consiglio verrà attivato solo temporaneamente durante la compilazione di byte difoo.el
, in modo che il significato dilexical-let
rimanga invariato per il resto di Emacs.Utilizzare una funzione macro/code-walker per compilare
let
di simboli non prefissati sulexical-let
con Emacsen precedente. Ciò si applicherebbe nuovamente solo durante la compilazione di byte difoo.el
.
Non allarmatevi se queste idee odore di overengineering: non sto proponendo di usarli così come sono. Sono interessato alle alternative alla macro di cui sopra, in cui il pacchetto ottiene il vantaggio di un utilizzo più portatile di chiusure per il prezzo di qualche complessità aggiuntiva di caricamento/compilazione.
EDIT 2
Come nessuno ha intensificato con una soluzione che permettesse il modulo di continuare a utilizzare let
o lexical-let
senza romperle per il resto della Emacs, sto accettando la risposta di Stefan, che afferma che la precedente macro è il modo per farlo. In aggiunta a ciò, la risposta migliora sul mio codice usando bound-and-true-p
e aggiungendo una dichiarazione elegante per edebug e lisp-indent.
Se qualcuno ha una proposta alternativa per questo livello di compatibilità o un'elegante implementazione delle idee di cui sopra, li incoraggio a rispondere.
Se stessimo scrivendo questo wrapper macro in un comune liff, probabilmente utilizzerei lo stesso approccio di base qui. Tranne che io nix 'l'eval, avendo un singolo defmacro bla-lexlet al livello più alto, e poi ho un costrutto-tempo se costrutto che determina quale modulo espandere il codice in (let o lessical-let in questo caso). Non sto mettendo questo come una risposta b/c è un approccio Lisp comune, e lo stesso approccio di base che hai usato. –
Bene, ora ho modificato l'esempio per spostare il parametro 'if' in macroexpansion-time. Tuttavia, gli argomenti contro "foo-lexlet" evidenziati nella domanda rimangono validi. – user4815162342