Con org-babel, come nominare i risultati di una chiamata di funzione e riutilizzarli


9

In org-mode, sto cercando di definire una funzione, una variabile e quindi assegnare a un'altra variabile il risultato della chiamata di funzione sulla prima variabile. Tuttavia, allora sembra che non sia possibile utilizzare questa nuova variabile nelle chiamate di funzioni successive.

Integrare le chiamate di funzione funziona, ma influire prima sul valore di una variabile consentirebbe un debug più rapido nel caso in cui qualcosa vada storto nella prima chiamata di funzione ed evitare la duplicazione di calcoli potenzialmente costosi.

MWE: (usare (require 'ob-emacs-lisp)se necessario)

#+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

L'espansione del secondo blocco di codice mostra:

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

Cosa mi sto perdendo?

(Questo è stato testato su emacs 24.3.1, 24.4 e 24.5, usando org 8.2.10)


qualcosa a che fare con Babele della Biblioteca, penso.
yi.tang.uni,

Risposte:


7

Aggiungi esplicitamente nuovo #+name:sopra il #+results:blocco.

Nota: aggiornato il codice da (message res)a (message (format "%s" res))per evitare che Wrong type argument: stringp, 2025causi ulteriore confusione.

#+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

Testato usando
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + Versione 3.10.9) Versione
Org-Mode: 8.2.10


Ok, questa è sicuramente la soluzione più semplice fino ad oggi. In questo caso, in realtà non è necessario inserire #+name:la #+call:riga prima , quindi non aggiunge alcuna contabilità al processo: basta nominare i risultati anziché la definizione. Forse non sembra naturale come potrebbe, ma almeno non è una soluzione alternativa per chiedere una soluzione alternativa.
T. Verron,

Questo è carino (+1). L'ho provato e funziona con la modalità org 8.2.7c. È interessante notare che una ricerca nella documentazione informativa della modalità Org -resultnon restituisce risultati. Si prega di aggiungere una nota che è necessario nominare la chiamata e che il nome del risultato deve essere il nome della chiamata con il suffisso -result. Almeno questo è quello che ho notato. (Se non si riesce a nominare la chiamata, la prossima rivalutazione aggiungerà un nuovo risultato ignorando il risultato nominato esistente.
Tobias,

@Tobias - Solo per chiarire, -resultè solo una convenzione di denominazione che ho usato per questo esempio. Se stai cercando esplicitamente i risultati di un blocco sorgente, aggiungi ()il nome quando passi il nome come variabile a un altro blocco o all'interno di un riferimento noweb.
Melioratus,

1
Sembra che l'unico requisito sia che il #+callnome sia. Il nome del risultato può essere scelto arbitrariamente. Se la chiamata non ha un nome, la chiamata genera una linea di risultato aggiuntiva senza nome.
Tobias,

C'è qualche sezione nel manuale che descrive quel comportamento?
Tobias,

3

È possibile utilizzare una :postroutine che restituisce il risultato come :name. Chiama il tuo babel-block con questo post routine e metti il ​​risultato in un cassetto. Nel seguente esempio questa routine post è denominata 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

Un altro modo per evitare il ricalcolo dei blocchi di codice è l' :cacheargomento header. Se questo è impostato yessul blocco di codice e i suoi argomenti vengono controllati per le modifiche e se non ci sono modifiche, il risultato precedente viene utilizzato senza rivalutazione del blocco di codice sorgente.

* 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"))

Grazie per gli hack! Sembra che entrambe le soluzioni funzionino, ma in qualche modo ci stiamo allontanando con la filosofia dell'org "provaci, funzionerà come ti aspetti". Se si scopre che non esiste altra soluzione, accetterò la risposta.
T. Verron,

@ T.Verron Penso che la seconda soluzione ( :cache yes) sia la soluzione standard. È anche descritto nel manuale dell'organizzazione (vedere la sezione 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` e presenta anche il vantaggio di disaccoppiare completamente i blocchi di codice. Anche se si modifica il primo blocco di codice e si tenta il secondo il primo non viene valutato. (A seconda dell'attività che può essere un vantaggio o uno svantaggio. Devi solo tenerlo a mente.)
Tobias,

Ero stanco la scorsa notte, non ho notato ... Anche se non ci fossero errori nella valutazione dell'ultimo blocco, funzionerebbe davvero meglio di quelli che ho scritto nella domanda? Dopotutto, il problema non è che rivaluta la chiamata per ogni riferimento (sarebbe anche un problema, e quindi sì, la cache sarebbe la soluzione), ma che non posso assolutamente fare riferimento.
T. Verron,

@ T.Verron Kyle Meyer ha ragione. Le modifiche orgmode.org/w/… non sono ancora entrate nel bagagliaio. La versione più recente è qui: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Ma, forse, ci sono cambiamenti incompatibili ...
Tobias,

@ T.Verron Sopra intendevo "rilascio stabile" e non "tronco". Mi dispiace per quello. Puoi vedere la mia risposta 1 come soluzione alternativa per la funzione mancante.
Tobias,

3

Ho il sospetto che devi solo aggiornare la tua modalità Org. Questo funziona sulla mia estremità (attuale versione di sviluppo del Org) e, in generale, dovrebbero funzionare come del tag release_8.3beta. Di seguito è riportato il commit che penso risolva il problema che stai descrivendo.

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.

Oltre a caricare Org dal repository git, un'altra opzione per eseguire una versione più recente è installare il pacchetto ELPA .


Bene, potrei non usare la versione di sviluppo, ma ciò non significa che non ho aggiornato dal 2013. Non sono così in ritardo. ;)Per essere precisi, il mio org-versionè 8.2.10. Ho modificato la domanda con queste informazioni, dove avrebbe dovuto essere in primo luogo.
T. Verron,

Spiacenti, mi dispiace per la disinformazione. Questo dovrebbe essere il commit, ma non è contenuto in 8.2.10.
Kyle Meyer,

Sapresti dove posso trovare una discussione su questo commit?
T. Verron,

Se esistesse una discussione a riguardo, molto probabilmente sarebbe nell'elenco della modalità Org, ma non ne ho trovato uno cercando, e non c'è un riferimento nel messaggio di commit, quindi potrebbe non essercene uno.
Kyle Meyer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.