Con org-babel, cómo nombrar los resultados de una llamada de función y reutilizarlos

9

En org-mode, estoy tratando de definir una función, una variable, y luego asignar a otra variable el resultado de la llamada a la función en la primera variable. Sin embargo, parece que no puedo usar esta nueva variable en llamadas de funciones posteriores.

La inclusión de las llamadas de función funciona, pero afectar primero el valor de una variable permitiría una depuración más rápida en caso de que algo salga mal en la primera llamada de función, y evitar duplicar cálculos potencialmente costosos.

MWE: (usar (require 'ob-emacs-lisp)si es necesario)

#+name: square
#+begin_src emacs-lisp :var x=3
  (message (format "%s" (* x x)))
#+end_src

#+RESULTS: square
: 9

#+name: value
: 45

#+name: squaredvalue
#+call: square(x=value)

#+RESULTS: squaredvalue
: 2025

Now I try to reuse this value: 

#+begin_src emacs-lisp :var res=squaredvalue
  (message res)
#+end_src

#+RESULTS:
: nil

Inlined calls do work:    

#+begin_src emacs-lisp :var res=square(value)
  (message res)
#+end_src

#+RESULTS:
: 2025

Expandir el segundo bloque de código muestra:

(let ((res (quote "nil")))
  (message res))

¿Qué me estoy perdiendo?

(Esto ha sido probado en emacs 24.3.1, 24.4 y 24.5, usando org 8.2.10)

T. Verron
fuente
algo que ver con Babel de la biblioteca, creo.
yi.tang.uni

Respuestas:

7

Explícitamente agregue nuevo #+name:sobre el #+results:bloque.

Nota: Actualizó su código de (message res)a (message (format "%s" res))para evitar que Wrong type argument: stringp, 2025a cause confusión adicional.

#+name: square
#+begin_src emacs-lisp :var x=3 
  (message (format "%s" (* x x)))
#+end_src

#+RESULTS: square
: 9

#+name: value
: 45

#+name: squaredvalue
#+call: square(x=value)

#+name: squaredvalue-results
#+RESULTS: squaredvalue
: 2025

#+begin_src emacs-lisp :var res=squaredvalue
   (message (format "%s" res))
#+end_src

#+RESULTS:
: nil


#+begin_src emacs-lisp :var res=squaredvalue-results
 (message (format "%s" res)) 
#+end_src

#+RESULTS:
: 2025

Probado con
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + Versión 3.10.9) Versión
Org-Mode: 8.2.10

Melioratus
fuente
Ok, esa es definitivamente la solución más simple hasta la fecha. En este caso, en realidad no hay necesidad de #+name:antes de la #+call:línea, por lo que no agrega ninguna contabilidad al proceso: solo nombra los resultados en lugar de la definición. Tal vez no se siente tan natural como podría, pero al menos eso no es una solución alternativa.
T. Verron
Esto es bueno (+1). Lo probé y funciona con el modo org 8.2.7c. Es interesante que una búsqueda en la documentación de información del modo Org -resultno arroje resultados. Agregue una nota de que se requiere nombrar la llamada y que el nombre del resultado debe ser el nombre de la llamada con el sufijo -result. Al menos eso es lo que noté. (Si no se le asigna un nombre a la llamada, la próxima reevaluación agregará un nuevo resultado ignorando el resultado con nombre existente.
Tobias
@Tobias: Solo para aclarar, -resultes solo una convención de nombres que utilicé para este ejemplo. Si está buscando explícitamente los resultados de un bloque fuente, agregue ()el nombre al pasar el nombre como variable a otro bloque o dentro de una referencia noweb.
Melioratus
1
Parece que el único requisito es que #+callse nombre el. El nombre del resultado puede elegirse arbitrariamente. Si la llamada no se nombra, la llamada genera una línea de resultado sin nombre adicional.
Tobias
¿Hay alguna sección en el manual que describa ese comportamiento?
Tobias
3

Puede usar una :postrutina que genera el resultado como :name. Llama a tu bloque de babel con esta rutina de publicación y coloca el resultado en un cajón. En el siguiente ejemplo, se nombra esta rutina de publicación asValue.

#+name: asValue
#+begin_src emacs-lisp :var name="last" :var val=0 :results drawer
(format "#+NAME: %s\n: %s" name val)
#+end_src

#+name: square
#+begin_src emacs-lisp :var x=3
(message "Running square")
(* x x)
#+end_src

#+RESULTS: square
: 9

#+NAME: value
: 45

#+call: square(value) :post asValue(name="squaredValue",val=*this*) :results drawer

#+RESULTS:
:RESULTS:
#+NAME: squaredValue
: 2025
:END:

Now I try to reuse this value: 

#+begin_src emacs-lisp  :var res=squaredValue
  (format "Re-used value: %s" res)
#+end_src

#+RESULTS:
: Re-used value: 2025

Otra forma de evitar volver a calcular los bloques de código es el :cacheargumento del encabezado. Si se establece en yesel bloque de código y se verifican los cambios en sus argumentos y si no hay cambios, el resultado anterior se usa sin una reevaluación del bloque de código fuente.

* Running of source blocks with caching

#+name: square
#+begin_src emacs-lisp :cache yes :var x=4
(message "Running square")
(* x x)
#+end_src

#+RESULTS[31bcff57ec9977f9b237fdc62ab18b1378b8c646]: square
: 16

#+NAME: value
: 40

#+name: squaredValue
#+begin_src emacs-lisp :cache yes :var x=square(x=value)
x
#+end_src

#+RESULTS[f90a5856e446c3120f7e91c4b77959598078526e]: squaredValue
: 1600

Now I try to reuse this value: 

#+begin_src emacs-lisp  :var res=squaredValue
  (format "Re-used value: %s" res)
#+end_src

#+RESULTS:
: Re-used value: 1600

Re-trying with call:

#+NAME: value2
: 20

#+NAME: squaredResult
#+call: square(x=value2) :cache yes

#+RESULTS[2f7c47d4c609a1a49ce00b4696afb7b5a5517b97]: squaredResult
: 400

The last version gives the following error with org-mode 8.2.4 in emacs 24.3.1.
(I do not know why.)

Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p nil)
  org-babel-set-current-result-hash("94ef10d9192a0be25e46238df4cf05389ff69040")
  org-babel-lob-execute(("square(x=value2)" ":cache yes" 0 "squaredResult"))
Tobias
fuente
Gracias por los hacks! Parece que ambas soluciones funcionan, pero de alguna manera nos estamos saltando con la filosofía de organización "solo pruébalo, funcionará de la manera que esperas". Si resulta que no hay otra solución, aceptaré la respuesta.
T. Verron
@ T.Verron Creo que la segunda solución ( :cache yes) es la solución estándar. También se describe en el manual de organización (consulte la sección 14.8.2.16 :cache'). It is a pity that it does not smoothly work with # + call . I think this is a bug. The first solution works with # + call` y también tiene la ventaja de que desacopla por completo los bloques de código. Incluso si edita el primer bloque de código y prueba el segundo, el primero no se evalúa (en función de la tarea que puede ser una ventaja o un disatvantage Sólo hay que tenerlo en cuenta..).
Tobias
Estuve cansado anoche, no me di cuenta ... Incluso si no hubiera ningún error en la evaluación del último bloque, ¿funcionaría realmente mejor que los que escribí en la pregunta? Después de todo, el problema no es que reevalúe la llamada para cada referencia (también sería un problema, y ​​sí, la solución sería la memoria caché), sino que no puedo hacer referencia a ella en absoluto.
T. Verron
@ T.Verron Kyle Meyer tiene razón. Los cambios orgmode.org/w/… todavía no se han introducido en el tronco. La versión más nueva está aquí: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Pero, tal vez, hay cambios incompatibles ...
Tobias
@ T.Verron Arriba, quise decir "versión estable" y no "troncal". Lo siento por eso. Puede ver mi respuesta 1 como solución para la función que falta.
Tobias
3

Sospecho que solo necesita actualizar su modo Org. Esto funciona en mi extremo (versión de desarrollo actual de Org) y, en general, debería funcionar a partir de la etiqueta release_8.3beta. A continuación se muestra la confirmación que creo soluciona el problema que está describiendo.

commit 1877652ce0234cf333fa103b5ada08fbf5946ab1
Date:   Wed Nov 13 11:42:40 2013 -0700

    allow reference to named call lines

    * lisp/ob-ref.el (org-babel-ref-resolve): Look for call lines when
      resolving references.

Además de cargar Org desde el repositorio de git, otra opción para ejecutar una versión más nueva es instalar el paquete ELPA .

Kyle Meyer
fuente
Bueno, no puede usar la versión de desarrollo, pero eso no quiere decir que no he actualizado desde 2013. No estoy de que tarde. ;)Para ser precisos, mi org-versiones 8.2.10. He editado la pregunta con esta información, donde debería haber estado en primer lugar.
T. Verron
Ooops, perdón por la desinformación. Ese debería ser el commit, pero no está contenido en 8.2.10.
Kyle Meyer
¿Sabrías dónde puedo encontrar una discusión sobre este compromiso?
T. Verron
Si existiera una discusión al respecto, lo más probable es que esté en la lista del modo Org, pero no encontré uno buscando, y no hay una referenciada en el mensaje de confirmación, por lo que puede que no haya una.
Kyle Meyer