2013-10-16 13 views
5

Ho presupposto che i valori passati in una funzione lisp siano assegnati a una quotazione che corrisponde al nome del parametro. Tuttavia, sono rimasto sorpreso dal fatto che:Come vengono memorizzati i parametri di funzione in lisp?

(defun test (x) (print (eval 'x))) 
(test 5) 

non funziona (la variabile x non è associata). Quindi se i parametri non sono memorizzati come simboli nella funzione, che cosa significa esattamente x in questo esempio? C'è un modo per accedere ai parametri da un simbolo che corrisponde al nome del parametro?

Altro contesto: Quello che vorrei fare è qualcosa di simile:

defun slice (r1 c1 r2 c2 board) 
    (dolist (param '(r1 c1 r2 c2)) ;adjust for negative indices 
    (if (< (eval param) 0) 
     (set param (+ (length board) (eval param))))) 
     ;Body of function 

Fondamentalmente, voglio scorrere i primi quattro parametri ed effettuare un adeguamento a qualsiasi dei loro valori, se sono < 0. Ovviamente, potrei fare un let e avere una singola riga per ogni parametro, ma considerando che sto facendo la stessa cosa per ciascuno dei quattro parametri questo sembrava più pulito. Tuttavia, ottengo l'errore che la variabile R1 non è associata.

+0

È implementazione specifica. [SBCL] (http://www.sbcl.org/manual/index.html) fornisce alcune informazioni nel capitolo Interfaccia funzioni esterne, ecc. –

risposta

4

C'è un modo per accedere ai parametri da un simbolo che corrisponde al nome del parametro?

Non per associazione lessicale. Common Lisp non consente di accedere a una variabile lessicale da un simbolo con nome simile. Dovresti dichiarare la variabile speciale.

Quindi, se i parametri non sono memorizzati come simboli nella funzione, che cosa significa esattamente x in questo esempio?

Un registro del processore? Una parte di una cornice dello stack?

Con binding dinamico:

CL-USER 40 > (defun foo (a b) 
       (declare (special a b)) 
       (dolist (v '(a b)) 
       (if (zerop (symbol-value v)) 
        (set v 10))) 
       (values a b)) 
FOO 

CL-USER 41 > (foo 1 0) 
1 
10 
+0

Grazie, questo mi ha permesso di usare lo stesso codice con solo una riga in più da dichiarare i parametri speciali – rcorre

+2

@murphyslaw Assicurati di comprendere le altre possibili conseguenze della dichiarazione di una variabile speciale. La variabile sarà associata con scope dinamico che significa, ad esempio, che '(let ((x 3)) (declare (special x)) (funcall (let ((x 4)) (declare (special x)) (lambda () x)))) 'restituirà' 3', non '4', anche se quando viene creata la funzione' lambda' 'x' è legato a' 4'. –

+0

@JoshuaTaylor - Grazie per il testa a testa, ho chiaramente bisogno di fare un po 'più di lettura su questo. Giusto per essere sicuro, dichiarare un parametro come speciale non avrà alcuna conseguenza per quel simbolo al di fuori del blocco funzione, corretto? – rcorre

2

Come ha spiegato Rainer, non è possibile accedere al valore di argomento lessicale con il suo nome.

Che cosa si può fare, invece è usare l'argomento &rest insieme destructuring-bind se si desidera che le variabili troppo:

(defun slice (board &rest params) 
    (destructuring-bind (r1 c1 r2 c2) 
     (mapcar (lambda (param) ;adjust for negative indices 
       (if (minusp param) 
        (+ (length board) param) 
        param)) 
       params) 
    ... operate on r1 c1 r2 c2 ...)) 
5

Questo è fondamentalmente come lessicale opere vincolanti: il nome della variabile viene sostituita entro l'ambito lessicale con una diretta riferimento a dove è memorizzato il valore della variabile. Il binding del nome della variabile symbol-value viene eseguito solo per la variabile dinamica che è possibile dichiarare con special.

Un modo per evitare di ripetere se stessi sarebbe una macro:

(defmacro with-adjusting ((&rest vars) adjust-value &body body) 
    `(let ,(loop for var in vars 
       collect `(,var (if (minusp ,var) 
           (+ ,var ,adjust-value) 
           ,var))) 
    ,@body)) 

(defun slice (r1 c1 r2 c2 board) 
    (with-adjusting (r1 c1 r2 c2) (length board) 
    ;; function body 
+1

Questa è una buona risposta. Una macro è abbastanza utile qui. Piccolo inconveniente: il codice compilato diventa più grande. –