2013-10-16 8 views
5

Ich nahm an, dass Werte, die in eine Lisp-Funktion übergeben wurden, einem Zitat zugewiesen werden, das dem Namen des Parameters entspricht. Allerdings war ich überrascht, dass dies:Wie werden Funktionsparameter in Lisp gespeichert?

funktioniert nicht (die Variable x ist ungebunden). Wenn also Parameter nicht als Symbole in der Funktion gespeichert sind, was genau ist dann in diesem Beispiel IS? Gibt es eine Möglichkeit, Parameter von einem Symbol aus aufzurufen, das mit dem Parameternamen übereinstimmt?

Weitere Kontext: Was Ich mag würde, ist, etwas zu tun wie folgt aus:

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 

Grundsätzlich möchte ich durch die ersten vier Parameter zu durchlaufen und eine Anpassung an alle ihre Werte machen, wenn sie < sind Natürlich könnte ich einen Let geben und eine individuelle Linie für jeden Parameter haben, aber wenn ich bedenke, dass ich dasselbe für jeden der vier Parameter tue, schien das sauberer zu sein. Allerdings bekomme ich den Fehler, dass die Variable R1 nicht gebunden ist.

+0

Es ist die Umsetzung spezifisch. [SBCL] (http://www.sbcl.org/manual/index.html) geben Sie einige Informationen im Kapitel Fremdfunktionsschnittstelle, etc. –

Antwort

4

Gibt es eine Möglichkeit, auf Parameter von einem Symbol zuzugreifen, das mit dem Parameternamen übereinstimmt?

Nicht für lexikalische Bindung. Common Lisp bietet keine Möglichkeit, auf eine lexikalische Variable aus einem ähnlichen benannten Symbol zuzugreifen. Sie müssten die Variable special deklarieren.

Wenn also Parameter nicht als Symbole in der Funktion gespeichert sind, was genau ist in diesem Beispiel IS?

Ein Prozessorregister? Ein Teil eines Stapelrahmens?

Bei dynamischer Bindung:

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

Danke, das erlaubte mir den gleichen Code mit nur einer zusätzlichen Zeile zu deklarieren die Parameter als Spezial – rcorre

+2

@murphyslaw Vergewissere dich, dass du die anderen möglichen Konsequenzen der Deklaration einer speziellen Variable verstehst. Die Variable wird mit dynamischem Gültigkeitsbereich gebunden, was zB bedeutet, dass (((x 3)) (deklarieren (spezielle x)) (funcall (let ((x 4)) (deklariere (spezielle x)) (lambda () x)))) 'wird' 3' zurückgeben, nicht '4', obwohl, wenn die' lambda'-Funktion erzeugt wird, 'x' an' 4' gebunden ist. –

+0

@JoshuaTaylor - Vielen Dank für die Heads-up, ich muss eindeutig mehr darüber lesen. Nur um sicher zu gehen, dass ein Parameter als speziell deklariert wird, hat keine Auswirkungen auf das Symbol außerhalb des Funktionsblocks, richtig? – rcorre

2

Wie Rainer erklärt, kann man nicht die lexikalische Argument durch seinen Namen zugreifen Wert.

Was können Sie tun, ist stattdessen die &rest Argument zusammen mit destructuring-bind, wenn Sie die Variablen wollen auch:

(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

Das ist im Grunde, wie lexikalische Bindung Werke: der Name der Variablen innerhalb des lexikalischen Gültigkeitsbereich mit einer direkten ersetzt wird Referenz auf wo der Wert der Variablen gespeichert wird. Das Binden des Variablennamens symbol-value erfolgt nur für dynamische Variablen, die Sie mit special deklarieren können.

Eine Möglichkeit Wiederholung zu vermeiden, sich selbst ein Makro sein würde:

(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

Das ist eine gute Antwort. Ein Makro ist hier sehr nützlich. Kleines Manko: Der kompilierte Code wird größer. –

Verwandte Themen