Avec org-babel, comment nommer les résultats d'un appel de fonction et les réutiliser

9

Dans org-mode, j'essaie de définir une fonction, une variable, puis d'assigner à une autre variable le résultat de l'appel de fonction sur la première variable. Cependant, il semble que je ne puisse pas utiliser cette nouvelle variable dans les appels de fonctions suivants.

L'insertion des appels de fonction fonctionne, mais affecter d'abord la valeur à une variable permettrait un débogage plus rapide en cas de problème lors du premier appel de fonction et éviterait de dupliquer des calculs potentiellement coûteux.

MWE: (utiliser (require 'ob-emacs-lisp)si nécessaire)

#+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'élargissement du deuxième bloc de code montre:

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

Qu'est-ce que je rate?

(Cela a été testé sur emacs 24.3.1, 24.4 et 24.5, en utilisant org 8.2.10)

T. Verron
la source
quelque chose à voir avec Babel of Library je pense.
yi.tang.uni

Réponses:

7

Ajoutez explicitement de nouveaux éléments #+name:au-dessus du #+results:bloc.

Remarque: mise à jour de votre code de (message res)à (message (format "%s" res))pour éviter que a Wrong type argument: stringp, 2025ne provoque une confusion supplémentaire.

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

Testé avec
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + version 3.10.9)
Version en mode organisationnel: 8.2.10

Melioratus
la source
Ok, c'est certainement la solution la plus simple à ce jour. Dans ce cas, il n'est en fait pas nécessaire de #+name:précéder la #+call:ligne, donc cela n'ajoute aucune comptabilité au processus: il suffit de nommer les résultats au lieu de la définition. Peut-être que cela ne semble pas aussi naturel que possible, mais au moins ce n'est pas une solution de contournement pour une solution alternative.
T. Verron
C'est sympa (+1). Je l'ai essayé et cela fonctionne avec le mode org 8.2.7c. Il est intéressant de noter que la recherche dans la documentation info du mode Org pour -resultne renvoie aucun résultat. Veuillez ajouter que la désignation de l'appel est obligatoire et que le nom du résultat doit être le nom de l'appel suffixé par -result. C'est du moins ce que j'ai noté. (Si l'on manque de nommer l'appel, la prochaine réévaluation ajoutera un nouveau résultat en ignorant le résultat nommé existant.
Tobias
@Tobias - Juste pour clarifier, -resultc'est juste une convention de nommage que j'ai utilisée pour cet exemple. Si vous recherchez explicitement les résultats d'un bloc source, ajoutez-le ()au nom lorsque vous passez le nom en tant que variable à un autre bloc ou dans une référence noweb.
Melioratus
1
On dirait que la seule exigence est que le #+callsoit nommé. Le nom du résultat peut être choisi arbitrairement. Si l'appel n'est pas nommé, une ligne de résultat supplémentaire sans nom est générée par l'appel.
Tobias
Y a-t-il une section dans le manuel qui décrit ce comportement?
Tobias
3

Vous pouvez utiliser une :postroutine qui génère le résultat sous la forme :name. Appelez votre babel-block avec cette routine de post et mettez le résultat dans un tiroir. Dans l'exemple suivant, cette routine de publication est nommée 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

Une autre façon d'éviter de recalculer les blocs de code est l' :cacheargument d'en-tête. Si ce paramètre est défini sur yesle bloc de code et ses arguments sont vérifiés pour les modifications et s'il n'y a pas de modifications, le résultat précédent est utilisé sans réévaluation du bloc de code source.

* 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
la source
Merci pour les hacks! Il semble que les deux solutions fonctionnent, mais nous nous en sortons quelque peu avec la philosophie de l'org. S'il s'avère qu'il n'y a pas d'autre solution, j'accepte la réponse.
T. Verron
@ T.Verron Je pense que la deuxième solution ( :cache yes) est la solution standard. Il est également décrit dans le manuel de l'organisation (voir section 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` et présente également l'avantage de découpler complètement les blocs de code. Même si vous éditez le premier bloc de code et essayez le second le premier n'est pas évalué. (Selon la tâche qui peut être un avantage ou un désavantage. Il suffit de garder cela à l'esprit.)
Tobias
J'étais fatigué la nuit dernière, je n'ai pas remarqué ... Même s'il n'y avait pas d'erreur lors de l'évaluation du dernier bloc, cela fonctionnerait-il vraiment mieux que ceux que j'ai écrits dans la question? Après tout, le problème n'est pas qu'il réévalue l'appel pour chaque référence (ce serait aussi un problème, et alors oui, le cache serait la solution), mais que je ne peux pas du tout le référencer.
T. Verron
@ T.Verron Kyle Meyer a raison. Les modifications orgmode.org/w/… ne sont pas encore entrées dans le coffre. La dernière version est ici: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Mais, peut-être, il y a des changements incompatibles ...
Tobias
@ T.Verron Ci-dessus, je voulais dire "version stable" et non "tronc". Désolé pour ça. Vous pouvez voir ma réponse 1 comme solution de contournement pour la fonctionnalité manquante.
Tobias
3

Je soupçonne que vous avez juste besoin de mettre à niveau votre mode Org. Cela fonctionne de mon côté (version en cours de développement d'Org) et devrait en général fonctionner à partir de la balise release_8.3beta. Vous trouverez ci-dessous le commit qui, je pense, résout le problème que vous décrivez.

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.

Outre le chargement d'Org à partir du dépôt git, une autre option pour exécuter une version plus récente consiste à installer le package ELPA .

Kyle Meyer
la source
Eh bien, je ne peux pas utiliser la version de développement, mais cela ne signifie pas que je n'ai pas mis à jour depuis 2013. Je ne suis pas si tard. ;)Pour être précis, mon org-versionest 8.2.10. J'ai édité la question avec cette information, où elle aurait dû être en premier lieu.
T. Verron
Oups, désolé pour la désinformation. Cela devrait être le commit, mais il n'est pas contenu dans 8.2.10.
Kyle Meyer
Savez-vous où je peux trouver une discussion sur ce commit?
T. Verron
Si une discussion à ce sujet existait, elle serait probablement sur la liste du mode Org, mais je n'en ai pas trouvé en recherchant, et il n'y en a pas de référencée dans le message de validation, donc il n'y en a peut-être pas.
Kyle Meyer