Dengan org-babel, cara memberi nama hasil panggilan fungsi dan menggunakannya kembali

9

Dalam org-mode, saya mencoba mendefinisikan fungsi, variabel, dan kemudian menetapkan ke variabel lain hasil dari panggilan fungsi pada variabel pertama. Namun, sepertinya saya tidak bisa menggunakan variabel baru ini dalam panggilan fungsi selanjutnya.

Menggarisbawahi panggilan fungsi tidak berfungsi, tetapi memengaruhi nilai ke variabel terlebih dahulu akan memungkinkan untuk debug lebih cepat jika terjadi kesalahan dalam panggilan fungsi pertama, dan untuk menghindari duplikasi perhitungan yang berpotensi mahal.

MWE: (gunakan (require 'ob-emacs-lisp)jika perlu)

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

Memperluas blok kode kedua menunjukkan:

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

Apa yang saya lewatkan?

(Ini telah diuji pada emacs 24.3.1, 24.4 dan 24.5, menggunakan org 8.2.10)

T. Verron
sumber
ada hubungannya dengan Babel dari Perpustakaan saya pikir.
yi.tang.uni

Jawaban:

7

Tambahkan secara eksplisit di #+name:atas #+results:blok baru.

Catatan: Diperbarui kode Anda dari (message res)ke (message (format "%s" res))untuk mencegah Wrong type argument: stringp, 2025dari menyebabkan kebingungan tambahan.

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

Diuji menggunakan
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + Versi 3.10.9)
Versi Mode Org: 8.2.10

Melioratus
sumber
Ok, itu pasti solusi paling sederhana untuk saat ini. Dalam hal ini, sebenarnya tidak perlu untuk baris #+name:sebelumnya #+call:, sehingga tidak menambahkan pembukuan ke proses: cukup beri nama hasil alih-alih definisi. Mungkin rasanya tidak sealami mungkin, tetapi setidaknya itu bukan solusi untuk mencari solusi alternatif.
T. Verron
Ini bagus (+1). Saya mencobanya dan berfungsi dengan mode-org 8.2.7c. Menarik bahwa pencarian dokumentasi info Mode Org untuk -resulttidak menghasilkan apa-apa. Harap tambahkan catatan bahwa penamaan panggilan diperlukan dan bahwa nama hasilnya harus nama panggilan yang diakhiri dengan -result. Setidaknya itulah yang saya catat. (Jika seseorang lupa menyebutkan panggilan, evaluasi ulang berikutnya akan menambah hasil baru dengan mengabaikan hasil yang ada.
Tobias
@Tobias - Hanya untuk memperjelas, -resulthanyalah konvensi penamaan yang saya gunakan untuk contoh ini. Jika Anda secara eksplisit mencari hasil dari blok sumber kemudian tambahkan ()ke nama ketika meneruskan nama sebagai variabel ke blok lain atau di dalam referensi noweb.
Melioratus
1
Tampak bahwa satu-satunya persyaratan adalah bahwa #+callitu dinamai. Nama hasilnya dapat dipilih secara sewenang-wenang. Jika panggilan tidak bernama, baris hasil tanpa nama tambahan dihasilkan oleh panggilan.
Tobias
Apakah ada bagian dalam manual yang menggambarkan perilaku itu?
Tobias
3

Anda dapat menggunakan :post-rutin yang menampilkan hasilnya sebagai :name. Panggil blok babel Anda dengan pos rutin ini dan masukkan hasilnya ke dalam laci. Dalam contoh berikut rutin posting ini dinamai 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

Cara lain untuk menghindari penghitungan ulang blok kode adalah :cacheargumen tajuk. Jika ini disetel ke yesblok kode dan argumennya diperiksa untuk perubahan dan jika tidak ada perubahan, hasil sebelumnya digunakan tanpa evaluasi ulang blok kode sumber.

* 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
sumber
Terima kasih atas peretasannya! Tampaknya kedua solusi tersebut berfungsi, tetapi kami agak menjauh dengan filosofi "coba saja, akan berfungsi seperti yang Anda harapkan" dari filosofi org. Jika ternyata tidak ada solusi lain, saya akan menerima jawabannya.
T. Verron
@ T. Verron Saya pikir solusi kedua ( :cache yes) adalah solusi standar. Hal ini juga dijelaskan dalam manual-org (lihat bagian 14.8.2.16 :cache'). It is a pity that it does not smoothly work with # + panggil . I think this is a bug. The first solution works with # + panggil` dan juga memiliki keuntungan bahwa itu sepenuhnya memisahkan blok kode. Bahkan jika Anda mengedit blok kode pertama dan mencoba yang kedua blok kode pertama dan coba yang kedua tidak dievaluasi. (Tergantung pada tugas yang mungkin menguntungkan atau tidak disukai. Anda hanya perlu mengingatnya.)
Tobias
Saya lelah tadi malam, saya tidak melihat ... Bahkan jika tidak ada kesalahan dalam evaluasi blok terakhir, apakah itu benar-benar bekerja lebih baik daripada yang saya tulis dalam pertanyaan? Lagi pula, masalahnya bukan itu mengevaluasi kembali panggilan untuk setiap referensi (itu akan menjadi masalah juga, dan kemudian ya, cache akan menjadi solusinya), tetapi saya tidak bisa referensi sama sekali.
T. Verron
@ T. Verron Kyle Meyer benar. Perubahan orgmode.org/w/… belum masuk ke bagasi. Versi terbaru ada di sini: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Tapi, mungkin, ada perubahan yang tidak kompatibel ...
Tobias
@ T. Verron Di atas saya maksudkan "rilis stabil" dan bukan "trunk". Maaf soal itu. Anda dapat melihat jawaban saya 1 sebagai solusi untuk fitur yang hilang.
Tobias
3

Saya menduga Anda hanya perlu meningkatkan mode Org Anda. Ini berfungsi pada saya (versi perkembangan saat ini dari Org) dan secara umum harus bekerja pada tag release_8.3beta. Di bawah ini adalah komit yang menurut saya memperbaiki masalah yang Anda gambarkan.

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.

Selain memuat Org dari git repo, opsi lain untuk menjalankan versi yang lebih baru adalah menginstal paket ELPA .

Kyle Meyer
sumber
Yah, aku mungkin tidak menggunakan versi pengembangan, tapi itu tidak berarti saya tidak diperbarui sejak 2013. Saya tidak yang terlambat. ;)Lebih tepatnya, saya org-versionadalah 8.2.10. Saya telah mengedit pertanyaan dengan informasi ini, di mana seharusnya di tempat pertama.
T. Verron
Aduh, maaf tentang informasi yang salah. Itu harus menjadi komit, tetapi tidak tercantum dalam 8.2.10.
Kyle Meyer
Apakah Anda tahu di mana saya dapat menemukan diskusi tentang komitmen ini?
T. Verron
Jika ada diskusi tentang hal itu, kemungkinan besar ada di daftar mode Org, tapi saya tidak menemukannya dengan mencari, dan tidak ada yang dirujuk dalam pesan komit, jadi mungkin tidak ada satu.
Kyle Meyer