¿Es posible adjuntar una cadena de documentos generada a una lambda?

10

Los documentos de Emacs dicen que cuando la cadena de documentos se coloca dentro lambdao defunse "almacena directamente en el objeto de función". Sin embargo, podemos cambiar documentos de funciones con nombre como este:

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

Pero el mismo truco no funciona con lambdas. ¿Hay alguna manera de agregar documentación a lambda? O de alguna manera generar dinámicamente doc-string literal?

Para aclarar, imagine la siguiente situación:

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

Me gustaría que la lambda tenga una cadena de documentos que mencione valores de fooy bar.

Mark Karpov
fuente

Respuestas:

12

Bueno, las lambdas pueden tener cadenas de documentos regulares como cualquier otra definición de función:

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

Entonces podrías usar:

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

Por qué desea una cadena de documentos en una función anónima es otra pregunta, que podría afectar el enfoque que adopte.

Por ejemplo, si planea vincularlo a una tecla y desea C-h kmostrar esa ayuda, puede usar este enfoque, pero, por supuesto, la ayuda también mostrará el objeto de función en sí (docstring incluido), lo que no es así estupendo; sin embargo, usted puede hacer esto y usted podría ver (también) la versión formateada bien-:

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

Sin embargo, es posible que prefiera usar un símbolo. Puede emparejar una función anónima con un símbolo no interno y no preocuparse de que entre en conflicto con cualquier otro símbolo del mismo nombre. Esto hace que la ayuda sea más limpia, ya que mostrará el nombre del símbolo en lugar del objeto de función. En este caso, tenemos la opción de pasar la cadena de documentación a en defaliaslugar de incrustarla en el formulario 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))))

o (y esto es casi lo mismo) podría capturar el símbolo no interno y establecer la propiedad del símbolo directamente, según su 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 nota al margen, tenga en cuenta que esta función solo va a sumar los valores permitidos para fooy barsi está utilizando lexical-binding: tpara su biblioteca. Si foo y bar están vinculados dinámicamente, las cadenas de documentos que he generado probablemente no sean precisas en tiempo de ejecución. Sin embargo, podemos atender esa situación con cadenas de documentos dinámicas . El nodo de información (elisp) Accessing Documentationdice de documentation-property:

Si el valor de la propiedad no es 'nulo', no es una cadena y no hace referencia al texto en un archivo, entonces se evalúa como una expresión Lisp para obtener una cadena.

Entonces, con cualquiera de los enfoques basados ​​en símbolos, podríamos citar el formulario de documentación para que se evalúe en el momento de la llamada:

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

En Emacs-25, hay una nueva característica exactamente para ese propósito:

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