Comprensione dei simboli non integrati e dell'espansione macro?


8

Voglio dimostrare la mia mancanza di conoscenza con un esempio.

Utilizzando le seguenti due definizioni macro,

(defmacro for (var from init to final do &rest body)
  "Execute a simple for loop: (for i from 1 to 10 do (print i))."
  (let ((tempvar 'max))
    `(let ((,var ,init)
           (,tempvar ,final))
       (while (<= ,var ,tempvar)
         ,@body
         (setq ,var (1+ ,var))))))
(defmacro for (var from init to final do &rest body)
  "Execute a simple for loop: (for i from 1 to 10 do (print i))."
  (let ((tempvar (make-symbol "max")))
    `(let ((,var ,init)
           (,tempvar ,final))
       (while (<= ,var ,tempvar)
         ,@body
         (setq ,var (1+ ,var))))))

la prima macro ombreggia qualsiasi variabile denominata maxche può verificarsi nel corpo e la seconda no, che può essere mostrata con il seguente esempio:

(let ((max 0)) ;; this variable is shadowed if the first macro defintion is used
  (for i from 1 to 3 do
       (setq square (* i i))
       (if (> square max) 
         (princ (format "\n%d %d" i square)))))

Per quanto ho imparato, la valutazione di una chiamata macro funziona in questo modo:

La macro viene valutata due volte. Innanzitutto il corpo viene valutato e restituisce un modulo. Questo modulo viene quindi valutato di nuovo.

Fin qui tutto bene.

Ma se suppongo che la macro restituisca davvero una porzione di testo che sembra essere una forma lisp, che viene poi interpretata, ottengo un conflitto che mi rende incapace di capire l'esempio sopra.

Quale pezzo di testo make-symbolrestituisce la seconda macro che utilizza , in modo che non si verifichino ombre? Nella mia comprensione, avrebbe senso un nome di simbolo scelto a caso estremamente estremo.

Se uso pp-macroexpand...entrambe le macro restituisco la stessa espansione.

Qualcuno è in grado di aiutarmi a uscire da questa confusione?


1
Non è un pezzo di testo, ma un elenco di simboli. Alcuni dei quali possono essere speciali e quindi non scontrarsi mai con altri ...
wasamasa,

2
Se si imposta print-gensyme print-circleper tvoi sarà in grado di vedere la differenza nelle espansioni di macro.
npostavs,

@wasamasa come sono speciali e cosa fanno funzionare questo è esattamente quello che voglio capire.
Clemera,

@npostavs Grazie, quindi il modulo restituito è diverso e questo non è visibile con le impostazioni predefinite .... Vedo che il simbolo non modificato viene sostituito da #:max. Cosa significa ? Sono molto interessato a maggiori dettagli.
Clemera,

3
Il #:è solo una convenzione della stampante per indicare un simbolo uninterned (questo è quello che print-gensymsi accende), non v'è più in dettaglio nel manuale: (elisp) Creating Symbols.
npostavs,

Risposte:


4

Come menzionato nei commenti, devi attivare questa impostazione per vedere come la macro-espansione funziona in modo più preciso. Nota che cambia solo il modo in cui macroexpandviene visualizzato, le macro funzionano ancora allo stesso modo in entrambi i casi:

(setq print-gensym t)

Quindi la prima istanza si espande in (errato):

(let ((max 0))
  (let ((i 1)
        (max 3))
    (while (<= i max)
      (setq square (* i i))
      (if (> square max)
          (princ
           (format "\n%d %d" i square)))
      (setq i (1+ i)))))

E il secondo si espande in (corretto):

(let ((max 0))
  (let
      ((i 1)
       (#:max 3))
    (while
        (<= i #:max)
      (setq square
            (* i i))
      (if
          (> square max)
          (princ
           (format "\n%d %d" i square)))
      (setq i
            (1+ i)))))

Per comprendere ulteriormente la differenza, considera di valutare questo:

(setq max 10)
;; => 10
(symbol-value 'max)
;; => 10
(symbol-value (make-symbol "max"))
;; => Caught unbound variable #:max, setting it to nil.
(make-symbol "max")
;; => #:max
(eq (make-symbol "max")
    (make-symbol "max"))
;; => nil

Come puoi vedere, il risultato di (make-symbol "max")non ha valore. Ciò garantisce la correttezza del primo passaggio di valutazione sulla macro. Con il secondo passaggio di valutazione, #:maxacquisisce un valore poiché è ora associato come variabile dinamica.


Dovresti anche print-circleaverne altri 2 #:maxche non lo sono eq(considera anche nidificato for).
npostavs,

Grazie, con la tua risposta e i commenti mi diventa molto più chiaro. Ma il nome del simbolo rimane max giusto? Quindi suppongo che l'interprete sappia che non è possibile cercare il massimo del simbolo non interessato nella consueta tabella dei simboli ma in un'altra tabella di ricerca ...
Clemera,

Al secondo passaggio, il simbolo max è una variabile legata al limite: tutto va bene in quel caso. Nel primo caso, è solo un simbolo uninternated unico - non c'è alcun tentativo di internarlo. Dai un'occhiata cl-gensymse non è ancora chiaro.
abo-ABO

Grazie per l'aiuto. Ho ancora problemi con i dettagli: al secondo passaggio c'è il limite massimo e il #: massimo e ancora non capisco come funziona che sono distinguibili. Se chiamo symbol-name sul make-symbol creato max è anche max. Allora perché l'interprete non è confuso, qual è il meccanismo che sa come cercare il giusto valore?
Clemera,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.