2016-10-02 9 views
2

Ich folge an article in dem der Autor das folgende Makro definiert:Was ist der Zweck der `internen` Funktion?

(defmacro make-is-integral-multiple-of (n) 
    (let ((function-name (intern (concatenate 
           'string 
           (symbol-name :is-integral-multiple-of-) 
           (write-to-string n))))) 
    `(defun ,function-name (x) 
     (equal 0 (mod x, n))))) 

Das Makro ist einfach zu lesen und zu verstehen, aber ich frage mich: Wann und warum brauchen wir ausdrücklich die intern Funktion?

Entfernen sie das Makro bricht, der dann den Fehler zurückgibt:

The value "IS-INTEGRAL-MULTIPLE-OF-3" 
is not of type 
    (OR SYMBOL CONS). 

Heißt das, dass intern muss jedes Mal aufgerufen werden, wird das Makro soll ein neues Symbol definieren? Gibt es irgendwelche Anwendungen von intern außerhalb einer defmacro Aussage? Einblicke sind willkommen.

Antwort

3

Funktionsnamen

Der Name einer Funktion vom Typ (OR SYMBOL CONS) sein muss. Dies wird vom Common-Lisp-Standard gefordert.

Daher muss der Name ein Symbol oder eine Liste sein. Normalerweise müssen Funktionsnamen in Lisp Symbole sein. Dass sie Listen sein können, ist relativ speziell für setf Funktionen. In Common Lisp kann es nur eine Liste wie (setf foo) sein, mit setf als erstes Symbol. Andere Listen als Funktionsnamen sind im einfachen Common Lisp nicht erlaubt.

Generieren von Funktionsnamen mit INTERN und MAKE-SYMBOL

Also, wenn Sie einen neuen Funktionsnamen generiert werden sollen, muss es ein Symbol sein. Erzeugen Sie zuerst den neuen Namen als String und generieren Sie dann ein Symbol aus diesem String.

Es gibt mehrere Möglichkeiten, ein Symbol zu erstellen. INTERN wird aussehen, wenn das Symbol bereits im Paket vorhanden ist (das aktuelle Paket ist der Standard). Wenn es nicht existiert, wird es ein neues erstellen und das Symbol in diesem Paket internieren.

Man könnte auch MAKE-SYMBOL verwenden, um ein Symbol zu erstellen, aber dieses Symbol wäre in keinem Paket enthalten. Dies macht es normalerweise schwierig, auf dieses Symbol zuzugreifen.

Normalerweise sollte ein Funktionsname ein Symbol sein, das in einem Paket interniert ist. Nur in seltenen Situationen, zum Beispiel in einigen Fällen von berechnetem Code, kann es nützlich sein, ein nicht durchbrochenes Symbol als Funktionsnamen zu haben.

3

intern findet oder erstellt ein Symbol mit dem angegebenen Namen in einem Paket.

Dies bedeutet, dass verwendet werden muss, wenn ein Makro ein Symbol erstellt. Das Makro in Ihrem Beispiel ist ein ziemlich typischer Anwendungsfall, mit der Ausnahme, dass Benutzer normalerweise nicht unterteilte Symbole wie #:is-integral-multiple-of- anstelle der Schlüsselwörter :is-integral-multiple-of- verwenden.

Es gibt andere Situationen, in denen es nützlich sein könnte. Im Allgemeinen ist ein Paket eine Tabelle für Sonderzwecke, die Zeichenfolgen Symbolen zuordnet, und intern entspricht .

Z. B. Sie eine der folgenden Methoden um Ihre Daten zu halten verwenden können:

(defvar *operators* (make-hash-table :test 'equal)) 
(defstruct operator name help function) 
(defun make-op (name help function) 
    (setf (gethash name *operators*) 
     (make-operator :name name 
         :help help 
         :function function))) 
(make-op "build-house" 
     "construct a house out of the supplied materials" 
     (lambda (bricks mortar) ...)) 
(funcall (operator-function (gethash "build-house" *operators*)) 
     (list "brick1" "brick2" ...) 
     (make-mortar)) 

oder

(defpackage #:operators) 
(defun make-op (name help function) 
    (let ((op (intern name #:operators))) 
    (setf (symbol-value op) help 
      (fdefinition op) function))) 
(make-op "build-house" 
     "construct a house out of the supplied materials" 
     (lambda (bricks mortar) ...)) 
(funcall #'operators::build-house 
     (list "brick1" "brick2" ...) 
     (make-mortar)) 

Name des Betreibers wird asscessed symbol-name verwendet wird, ist Hilfe symbol-value.