Можно ли прикрепить сгенерированную строку документа к лямбде?

10

Документы Emacs говорят, что когда строка документа помещается внутрь lambdaили defunона «хранится непосредственно в объекте функции». Тем не менее, мы можем изменить документы именованных функций следующим образом:

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

Но тот же трюк не работает с лямбдами. Есть ли способ добавить документацию в лямбду? Или как-то динамически генерировать строковый литерал?

Чтобы уточнить, представьте следующую ситуацию:

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

Я хотел бы, чтобы лямбда имела строку документа, которая упоминает значения fooи bar.

Марк Карпов
источник

Ответы:

12

Ну, лямбды могут иметь обычные строки документов, как и любое другое определение функции:

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

Таким образом, вы можете использовать:

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

Почему вам нужна строка документа для анонимной функции - это другой вопрос, который может повлиять на ваш подход.

Например, если вы планируете привязать его к клавише и хотите C-h kотобразить эту справку, вы можете использовать этот подход, но, конечно, в справке также будет отображаться сам объект функции (включая строку документации), что не так Великий; тем не менее , вы могли бы сделать это , и вы бы (и) увидеть красиво отформатированный вариант:

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

Вы можете предпочесть использовать символ, однако. Вы можете связать анонимную функцию с неинтернизированным символом и не беспокоиться о том, что она конфликтует с любыми другими символами с таким же именем. Это делает справку более чистой, поскольку она отображает имя символа, а не объект функции. В этом случае у нас есть возможность передать строку документации defaliasвместо ее встраивания в лямбда-форму.

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

или (и это очень одно и то же) вы можете перехватить неинтернизированный символ и напрямую установить свойство символа в соответствии с исходным кодом:

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

В качестве примечания, имейте в виде , что эта функция только будет суммирование Выпускаемого переплета значения fooи , barесли вы используете lexical-binding: tдля вашей библиотеки. Если foo и bar динамически связаны, сгенерированные мной строки документации, скорее всего, не будут точными во время выполнения. Тем не менее, мы можем удовлетворить эту ситуацию с помощью динамических строк документации. Информационный узел (elisp) Accessing Documentationговорит о documentation-property:

Если значение свойства не равно nil, не является строкой и не ссылается на текст в файле, то оно вычисляется как выражение Lisp для получения строки.

Таким образом, с любым из подходов, основанных на символах, мы могли бы процитировать форму документации, чтобы оценить ее во время вызова:

(defalias (make-symbol "a-foo-bar-function")
   (lambda ()
     (interactive)
     (+ foo bar))
   '(format "Function which sums foo=%s and bar=%s" foo bar))
Phils
источник
13

В Emacs-25 для этой цели есть новая функция:

(let ((foo 1)
      (bar 2))
  (lambda ()
    (:documentation (format "Return the sum of %d and %d." foo bar))
    (+ foo bar)))
Стефан
источник