É possível anexar a sequência de documentos gerada a um lambda?

10

Os documentos do Emacs dizem que quando a string de documento é colocada dentro lambdaou defuné "armazenada diretamente no objeto de função". No entanto, podemos alterar documentos de funções nomeadas como esta:

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

Mas o mesmo truque não funciona com lambdas. Existe uma maneira de adicionar documentação ao lambda? Ou, de alguma forma, gerar dinamicamente literal de string de documento?

Para esclarecer, imagine a seguinte situação:

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

Gostaria que o lambda tivesse uma string de documento que mencione valores de fooe bar.

Mark Karpov
fonte

Respostas:

12

Bem, lambdas podem ter documentos regulares como qualquer outra definição de função:

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

Então você pode usar:

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

Por que você deseja uma sequência de documentos em uma função anônima é outra questão, que pode afetar a abordagem adotada.

Por exemplo, se você planeja vinculá-lo a uma chave e deseja C-h kexibir essa ajuda, pode usar essa abordagem, mas é claro que a ajuda ainda exibirá o próprio objeto de função (incluindo a doutrina), o que não é tão importante. ótimo; no entanto, você poderia fazer isso e veria (também) a versão bem formatada:

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

Você pode preferir usar um símbolo, no entanto. Você pode emparelhar uma função anônima com um símbolo não interno e não se preocupar com o conflito com outros símbolos com o mesmo nome. Isso torna a ajuda mais limpa, pois exibirá o nome do símbolo em vez do objeto de função. Nesse caso, temos a opção de passar a docstring para, em defaliasvez de incorporá-la no formato 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 (e isso é praticamente a mesma coisa), você pode capturar o símbolo não interno e definir a propriedade do símbolo diretamente, conforme seu código original:

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

Como uma nota lateral, estar ciente de que esta função é única vai ser somando os valores obrigado a deixar para fooe barse você estiver usando lexical-binding: tpara a sua biblioteca. Se foo e bar forem vinculados dinamicamente, as doutrinas que eu gerei provavelmente não serão precisas em tempo de execução. Podemos realmente atender a essa situação com doutrinas dinâmicas , no entanto. O nó Informações (elisp) Accessing Documentationdiz sobre documentation-property:

Se o valor da propriedade não for 'nil', não for uma sequência e não se referir ao texto em um arquivo, será avaliada como uma expressão Lisp para obter uma sequência.

Portanto, com qualquer uma das abordagens baseadas em símbolos, poderíamos citar o formulário da documentação para que ele seja avaliado no momento da chamada:

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

No Emacs-25, há um novo recurso exatamente para esse fim:

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