Ist es möglich, eine generierte Dokumentzeichenfolge an ein Lambda anzuhängen?

10

Emacs-Dokumente geben an, dass wenn eine Dokumentzeichenfolge in das Objekt eingefügt lambdaoder defun"direkt im Funktionsobjekt gespeichert" wird. Wir können jedoch Dokumente benannter Funktionen wie folgt ändern:

(put 'my-function-name 'function-documentation "Blah.")

Aber der gleiche Trick funktioniert nicht mit Lambdas. Gibt es eine Möglichkeit, Lambda eine Dokumentation hinzuzufügen? Oder irgendwie dynamisch ein Doc-String-Literal generieren?

Stellen Sie sich zur Verdeutlichung die folgende Situation vor:

(let ((foo 1)
      (bar 2))
  (lambda ()
    (+ foo bar)))

Ich möchte, dass das Lambda eine Dokumentzeichenfolge hat, in der die Werte von foound erwähnt werden bar.

Mark Karpov
quelle

Antworten:

12

Nun, Lambdas können wie jede andere Funktionsdefinition reguläre Docstrings haben:

(lambda ()
   "I'm a docstring!"
   (+ foo bar))

Sie könnten also verwenden:

(let ((foo 1)
      (bar 2))
  `(lambda ()
     ,(format "Function which sums foo=%s and bar=%s" foo bar)
     (+ foo bar)))

Warum Sie eine Dokumentzeichenfolge für eine anonyme Funktion wünschen, ist eine andere Frage, die sich auf Ihren Ansatz auswirken kann.

Wenn Sie beispielsweise vorhaben, es an einen Schlüssel zu binden, und C-h kdiese Hilfe anzeigen möchten , können Sie diesen Ansatz verwenden. In der Hilfe wird jedoch weiterhin auch das Funktionsobjekt selbst angezeigt (einschließlich Dokumentzeichenfolge), was nicht der Fall ist großartig; Trotzdem könnten Sie dies tun und Sie würden (auch) die schön formatierte Version sehen:

(global-set-key
 (kbd "C-c a")
 (let ((foo 1)
       (bar 2))
   `(lambda ()
      ,(format "Function which sums foo=%s and bar=%s" foo bar)
      (interactive)
      (+ foo bar))))

Möglicherweise möchten Sie jedoch lieber ein Symbol verwenden. Sie können eine anonyme Funktion mit einem nicht internierten Symbol koppeln , ohne sich Sorgen machen zu müssen, dass sie mit anderen gleichnamigen Symbolen in Konflikt steht. Dies macht die Hilfe sauberer, da der Symbolname und nicht das Funktionsobjekt angezeigt wird. In diesem Fall haben wir die Möglichkeit, die Dokumentzeichenfolge an zu übergeben, defaliasanstatt sie in das Lambda-Formular einzubetten .

(global-set-key
 (kbd "C-c a")
 (let ((foo 1)
       (bar 2))
   (defalias (make-symbol "a-foo-bar-function")
     (lambda ()
       (interactive)
       (+ foo bar))
     (format "Function which sums foo=%s and bar=%s" foo bar))))

oder (und das ist sehr ähnlich) Sie könnten das nicht interternierte Symbol erfassen und die Symboleigenschaft direkt gemäß Ihrem ursprünglichen Code festlegen:

(global-set-key
 (kbd "C-c a")
 (let ((foo 1)
       (bar 2)
       (sym (make-symbol "a-foo-bar-function")))
   (put sym 'function-documentation
        (format "Function which sums foo=%s and bar=%s" foo bar))
   (defalias sym
     (lambda ()
       (interactive)
       (+ foo bar)))))

Beachten Sie als Randnotiz, dass diese Funktion nur die zulässigen Werte für foound summiert, barwenn Sie sie lexical-binding: tfür Ihre Bibliothek verwenden. Wenn foo und bar dynamisch gebunden sind, sind die von mir generierten Dokumentzeichenfolgen zur Laufzeit höchstwahrscheinlich nicht genau. Wir können dieser Situation jedoch mit dynamischen Dokumentenstrings gerecht werden . Info-Knoten (elisp) Accessing Documentationsagt von documentation-property:

Wenn der Eigenschaftswert nicht 'nil' ist, keine Zeichenfolge ist und sich nicht auf Text in einer Datei bezieht, wird er als Lisp-Ausdruck ausgewertet, um eine Zeichenfolge zu erhalten.

Bei jedem der symbolbasierten Ansätze können wir das Dokumentationsformular zitieren, damit es zum Zeitpunkt des Anrufs ausgewertet wird:

(defalias (make-symbol "a-foo-bar-function")
   (lambda ()
     (interactive)
     (+ foo bar))
   '(format "Function which sums foo=%s and bar=%s" foo bar))
Phils
quelle
13

In Emacs-25 gibt es genau zu diesem Zweck eine neue Funktion:

(let ((foo 1)
      (bar 2))
  (lambda ()
    (:documentation (format "Return the sum of %d and %d." foo bar))
    (+ foo bar)))
Stefan
quelle