W org-babel: jak nazwać wyniki wywołania funkcji i użyć ich ponownie

9

W org-modepróbuję zdefiniować funkcję, zmienna, a następnie przypisanie innej zmiennej wynik wywołania funkcji o zmiennej pierwszy. Wydaje się jednak, że nie mogę użyć tej nowej zmiennej w kolejnych wywołaniach funkcji.

Wstawianie wywołań funkcji działa, ale najpierw wpływanie na wartość zmiennej umożliwi szybsze debugowanie w przypadku, gdy coś pójdzie nie tak w pierwszym wywołaniu funkcji, i uniknie powielania potencjalnie kosztownych obliczeń.

MWE: (użyj w (require 'ob-emacs-lisp)razie potrzeby)

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

Rozwinięcie drugiego bloku kodu pokazuje:

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

czego mi brakuje?

(Zostało to przetestowane na emacs 24.3.1, 24.4 i 24.5, przy użyciu org 8.2.10)

T. Verron
źródło
myślę, że ma to coś wspólnego z Babel of Library.
yi.tang.uni

Odpowiedzi:

7

Jawnie dodaj nowy #+name:powyżej #+results:bloku.

Uwaga: Aktualizacja kodu od (message res)celu (message (format "%s" res)), aby zapobiec Wrong type argument: stringp, 2025od powodując dodatkowe zamieszanie.

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

Testowane przy użyciu
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + wersja 3.10.9)
Wersja trybu org: 8.2.10

Melioratus
źródło
Ok, to zdecydowanie najprostsze jak dotąd rozwiązanie. W tym przypadku tak naprawdę nie ma potrzeby #+name:poprzedzania #+call:wiersza, więc nie dodaje on żadnej księgowości do procesu: wystarczy nazwać wyniki zamiast definicji. Może to nie wydaje się tak naturalne, jak mogłoby, ale przynajmniej nie jest to obejście błagające o alternatywne rozwiązanie.
T. Verron
To jest fajne (+1). Próbowałem i działa z trybem org 8.2.7c. Ciekawe, że wyszukiwanie w dokumentacji informacyjnej Trybu -resultOrganizacji nie zwraca żadnych wyników. Dodaj notatkę, że nazywanie połączenia jest wymagane, a nazwa wyniku musi być nazwą połączenia z przyrostkiem -result. Przynajmniej tak zauważyłem. (Jeśli nie uda się nazwać połączenia, następna ponowna ocena doda nowy wynik, ignorując istniejący nazwany wynik.
Tobias
@Tobias - dla wyjaśnienia, -resultto tylko konwencja nazewnictwa, której użyłem w tym przykładzie. Jeśli wprost szukasz wyników bloku źródłowego, dodaj ()go do nazwy, przekazując nazwę jako zmienną do innego bloku lub wewnątrz odwołania do nowegob.
Melioratus
1
Wygląda na to, że jedynym wymaganiem #+calljest nazwa. Nazwę wyniku można wybrać dowolnie. Jeśli połączenie nie zostanie nazwane, wówczas wywołanie generuje dodatkową nienazwaną linię wyniku.
Tobias
Czy w instrukcji jest jakaś sekcja opisująca to zachowanie?
Tobias
3

Możesz użyć :post-routine, która wyświetla wynik jako :name. Zadzwoń do swojego bloku babel przy pomocy tej procedury postu i umieść wynik w szufladzie. W poniższym przykładzie procedura ta została nazwana 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

Innym sposobem uniknięcia ponownego obliczania bloków kodu jest :cacheargument nagłówka. Jeśli jest ustawiony na yesblok kodu, a jego argumenty są sprawdzane pod kątem zmian, a jeśli nie ma zmian, poprzedni wynik jest używany bez ponownej oceny bloku kodu źródłowego.

* 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"))
Tobiasz
źródło
Dzięki za włamania! Wydaje się, że oba rozwiązania działają, ale w pewnym sensie uciekamy od filozofii „po prostu spróbuj, zadziała tak, jak tego oczekujesz”. Jeśli okaże się, że nie ma innego rozwiązania, zaakceptuję odpowiedź.
T. Verron,
@ T.Verron Myślę, że drugie rozwiązanie ( :cache yes) jest rozwiązaniem standardowym. Jest to również opisane w podręczniku organizacji (patrz rozdział 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`, a także ma tę zaletę, że całkowicie oddziela bloki kodu. Nawet jeśli edytujesz pierwszy blok kodu i wypróbujesz drugi z nich, pierwszy nie jest oceniany (w zależności od zadania, które może być zaletą lub wadą. Musisz o tym pamiętać).
Tobias
Byłem zmęczony zeszłej nocy, nie zauważyłem ... Nawet jeśli przy ocenie ostatniego bloku nie wystąpił błąd, czy to naprawdę działałoby lepiej niż te, które napisałem w pytaniu? W końcu problem nie polega na tym, że ponownie ocenia połączenie dla każdego odwołania (to też byłby problem, a następnie tak, rozwiązaniem byłoby buforowanie), ale że w ogóle nie mogę go odwoływać.
T. Verron
@ T.Verron Kyle Meyer ma rację. Zmiany orgmode.org/w/… nie znalazły się jeszcze w bagażniku. Najnowsza wersja jest tutaj: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Ale być może nastąpiły niezgodne zmiany ...
Tobias
@ T.Verron Powyżej miałem na myśli „stabilne wydanie”, a nie „bagażnik”. Przepraszam za to. Możesz zobaczyć moją odpowiedź 1 jako obejście brakującej funkcji.
Tobias
3

Podejrzewam, że musisz tylko zaktualizować swój tryb Org. Działa to na moim końcu (obecna wersja rozwojowa Org) i ogólnie powinno działać od tagu release_8.3beta. Poniżej znajduje się zatwierdzenie, które moim zdaniem rozwiązuje problem, który opisujesz.

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.

Oprócz ładowania Orga z repozytorium git, inną opcją do uruchomienia nowszej wersji jest instalacja pakietu ELPA .

Kyle Meyer
źródło
Cóż, nie mogą korzystać z wersji rozwojowej, ale to nie znaczy, że nie są aktualizowane od 2013 roku nie jestem , że późno. ;)Mówiąc org-versionściślej , moja to 8.2.10. Zredagowałem pytanie z tą informacją, gdzie powinno być na pierwszym miejscu.
T. Verron,
Ups, przepraszam za wprowadzanie w błąd. To powinno być zatwierdzenie, ale nie jest zawarte w 8.2.10.
Kyle Meyer,
Czy wiesz, gdzie mogę znaleźć dyskusję na temat tego zatwierdzenia?
T. Verron
Gdyby istniała dyskusja na ten temat, najprawdopodobniej byłaby na liście trybów Organizacji, ale nie znalazłem jej podczas wyszukiwania i nie ma żadnej wzmianki w komunikacie zatwierdzenia, więc może jej nie być.
Kyle Meyer