Est-il possible d'attacher une chaîne de doc générée à un lambda?

10

Les documents Emacs indiquent que lorsque la chaîne doc est placée à l'intérieur de lambdaou defunest «stockée directement dans l'objet fonction». Cependant, nous pouvons changer la documentation des fonctions nommées comme ceci:

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

Mais la même astuce ne fonctionne pas avec les lambdas. Existe-t-il un moyen d'ajouter de la documentation à lambda? Ou en quelque sorte générer dynamiquement un littéral de chaîne de doc?

Pour clarifier, imaginez la situation suivante:

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

Je voudrais que le lambda ait une chaîne de doc qui mentionne les valeurs de fooet bar.

Mark Karpov
la source

Réponses:

12

Les lambdas peuvent avoir des docstrings réguliers comme n'importe quelle autre définition de fonction:

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

Vous pouvez donc utiliser:

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

Pourquoi vous voulez une docstring sur une fonction anonyme est une autre question, qui pourrait affecter l'approche que vous adoptez.

Par exemple, si vous prévoyez de le lier à une clé et que vous souhaitez C-h kafficher cette aide, vous pouvez utiliser cette approche, mais bien sûr, l'aide affichera également l'objet de fonction lui-même (docstring inclus), ce qui n'est pas le cas génial; néanmoins, vous pourriez le faire et vous verriez (également) la version bien formatée:

(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))))

Vous pouvez cependant préférer utiliser un symbole. Vous pouvez associer une fonction anonyme à un symbole non interne , et ne vous inquiétez pas qu'elle entre en conflit avec d'autres symboles du même nom. Cela rend l'aide plus propre, car elle affichera le nom du symbole plutôt que l'objet fonction. Dans ce cas, nous avons la possibilité de passer la docstring à defaliasau lieu de l'intégrer sous la forme lambda.

(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))))

ou (et c'est à peu près la même chose), vous pouvez capturer le symbole non interne et définir directement la propriété du symbole, selon votre code d'origine:

(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)))))

En guise de remarque, sachez que cette fonction va uniquement additionner les valeurs autorisées pour fooet barsi vous utilisez lexical-binding: tpour votre bibliothèque. Si foo et bar sont liés dynamiquement, les docstrings que j'ai générés ne seront probablement pas précis au moment de l'exécution. Nous pouvons en fait répondre à cette situation avec des docstrings dynamiques . Le noeud d'information (elisp) Accessing Documentationdit documentation-property:

Si la valeur de la propriété n'est pas 'nil', n'est pas une chaîne et ne fait pas référence au texte dans un fichier, alors elle est évaluée comme une expression Lisp pour obtenir une chaîne.

Donc, avec n'importe laquelle des approches basées sur les symboles, nous pourrions citer le formulaire de documentation afin de le faire évaluer au moment de l'appel:

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

Dans Emacs-25, il y a une nouvelle fonctionnalité exactement à cet effet:

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