12

Emacs docs say that when doc string is put inside of lambda or defun it's “stored directly in the function object”. However, we can change docs of named functions like this:

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

But the same trick doesn't work with lambdas. Is there a way to add documentation to lambda? Or somehow dynamically generate doc-string literal?

To clarify, imagine the following situation:

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

I would like the lambda to have a doc string that mentions values of foo and bar.

Drew
  • 75,699
  • 9
  • 109
  • 225
Mark Karpov
  • 4,893
  • 1
  • 24
  • 53

2 Answers2

16

In Emacs-25, there's a new feature exactly for that purpose:

(let ((foo 1)
      (bar 2))
  (lambda ()
    (:documentation (format "Return the sum of %d and %d." foo bar))
    (+ foo bar)))
Stefan
  • 26,154
  • 3
  • 46
  • 84
13

Well lambdas can have regular docstrings just like any other function definition:

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

So you could use:

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

Why you want a docstring on an anonymous function is another question, which might affect the approach you take.

For instance if you're planning to bind it to a key and you want C-h k to display that help, you could use this approach, but of course the help will still also display the function object itself (docstring included), which isn't so great; nevertheless you could do this and you would (also) see the nicely-formatted version:

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

You may prefer to use a symbol, however. You can pair an anonymous function with an uninterned symbol, and not worry about it conflicting with any other symbols of the same name. This makes the help cleaner, as it will display the symbol name rather than the function object. In this instance we have the option of passing the docstring to defalias instead of embedding it in the lambda form.

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

or (and this is very much the same thing) you could capture the uninterned symbol, and set the symbol property directly, as per your original code:

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

As a side note, be aware that this function is only going to be summing the let-bound values for foo and bar if you're using lexical-binding: t for your library. If foo and bar are dynamically bound, the docstrings I've generated would most likely not be accurate at run-time. We can actually cater to that situation with dynamic docstrings, though. Info node (elisp) Accessing Documentation says of documentation-property:

If the property value isn’t ‘nil’, isn’t a string, and doesn’t refer to text in a file, then it is evaluated as a Lisp expression to obtain a string.

So with any of the symbol-based approaches, we could quote the documentation form in order to have it evaluated at call time:

(defalias (make-symbol "a-foo-bar-function")
   (lambda ()
     (interactive)
     (+ foo bar))
   '(format "Function which sums foo=%s and bar=%s" foo bar))
phils
  • 48,657
  • 3
  • 76
  • 115