Com org-babel, como nomear os resultados de uma chamada de função e reutilizá-los

9

Em org-mode, estou tentando definir uma função, uma variável e, em seguida, atribuindo a outra variável o resultado da chamada de função na primeira variável. No entanto, parece que não posso usar essa nova variável em chamadas de funções subseqüentes.

A inclusão de chamadas de função funciona, mas afetar o valor de uma variável primeiro permitiria uma depuração mais rápida, caso algo desse errado na primeira chamada de função, e evitar duplicação de cálculos potencialmente caros.

MWE: (use (require 'ob-emacs-lisp)se necessário)

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

A expansão do segundo bloco de código mostra:

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

o que estou perdendo?

(Isso foi testado no emacs 24.3.1, 24.4 e 24.5, usando a organização 8.2.10)

T. Verron
fonte
algo a ver com Babel da Biblioteca, eu acho.
yi.tang.uni

Respostas:

7

Adicione explicitamente novo #+name:acima do #+results:bloco.

Nota: Atualize seu código de (message res)para (message (format "%s" res))para impedir que um Wrong type argument: stringp, 2025cause confusão 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

Testado usando o
GNU Emacs 24.4.1 (x86_64-unknown-cygwin, GTK + versão 3.10.9)
Versão no modo organizacional: 8.2.10

Melioratus
fonte
Ok, essa é definitivamente a solução mais simples até o momento. Nesse caso, na verdade não há necessidade de #+name:antes da #+call:linha, portanto, não adiciona nenhuma contabilidade ao processo: apenas nomeie os resultados em vez da definição. Talvez não pareça tão natural quanto possível, mas pelo menos isso não é uma solução alternativa que implora por uma solução alternativa.
T. Verron
Isso é legal (+1). Eu tentei e funciona com o modo org 8.2.7c. Interessante que uma pesquisa na documentação de informações do Modo organizacional -resultnão retorne resultados. Adicione uma observação de que é necessário nomear a chamada e que o nome do resultado deve ser o nome da chamada com o sufixo -result. Pelo menos foi o que eu notei. (Se alguém falhar em nomear a chamada, a próxima reavaliação adicionará um novo resultado, ignorando o resultado nomeado existente.
Tobias
@ Tobias - Só para esclarecer, -resulté apenas uma convenção de nomenclatura que usei para este exemplo. Se você estiver procurando explicitamente os resultados de um bloco de origem, adicione ()-o ao passar o nome como uma variável para outro bloco ou dentro de uma referência noweb.
Melioratus 26/05
11
Parece que o único requisito é que #+callnomeado. O nome do resultado pode ser escolhido arbitrariamente. Se a chamada não for nomeada, uma linha de resultado adicional sem nome será gerada pela chamada.
Tobias
Existe alguma seção no manual que descreva esse comportamento?
Tobias
3

Você pode usar uma :postrotina-que gera o resultado como :name. Ligue para o seu bloco de notas com esta rotina de postagem e coloque o resultado em uma gaveta. No exemplo a seguir, essa rotina de postagem é nomeada 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

Outra maneira de evitar o recálculo dos blocos de código é o :cacheargumento do cabeçalho. Se isso estiver definido como yeso bloco de código e seus argumentos forem verificados quanto a alterações e se não houver alterações, o resultado anterior será usado sem reavaliação do bloco de código-fonte.

* 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
fonte
Obrigado pelos hacks! Parece que as duas soluções funcionam, mas estamos nos saindo um pouco da filosofia "apenas tente, funcionará da maneira que você espera" na organização. Se acontecer que não há outra solução, aceitarei a resposta.
T. Verron 25/05
@ T.Verron Acho que a segunda solução ( :cache yes) é a solução padrão. Ele também é descrito no manual (consulte a seção 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 também tem a vantagem de desacoplar completamente os blocos de código. Mesmo se você editar o primeiro bloco de código e tentar o segundo, o primeiro não é avaliado (Dependendo da tarefa que pode ser uma vantagem ou um disatvantage Você apenas tem que manter isso em mente..).
Tobias
Eu estava cansado ontem à noite, não percebi ... Mesmo que não houvesse erro na avaliação do último bloco, isso realmente funcionaria melhor do que os que escrevi na pergunta? Afinal, o problema não é o fato de reavaliar a chamada para cada referência (também seria um problema e, sim, o cache seria a solução), mas não posso fazer referência a ela.
T. Verron
@ T.Verron Kyle Meyer está certo. As alterações orgmode.org/w/… ainda não entraram no tronco. A versão mais recente está aqui: orgmode.org/w/?p=org-mode.git;a=blob_plain;f=lisp/… . Mas, talvez, há mudanças incompatíveis ...
Tobias
@ T.Verron Acima, eu quis dizer "liberação estável" e não "tronco". Me desculpe por isso. Você pode ver minha resposta 1 como solução alternativa para o recurso ausente.
Tobias
3

Eu suspeito que você só precisa atualizar o modo Org. Isso funciona no meu final (versão atual de desenvolvimento da organização) e, em geral, deve funcionar como na tag release_8.3beta. Abaixo está o commit que acho que corrige o problema que você está descrevendo.

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.

Além de carregar a Org a partir do repositório git, outra opção para executar uma versão mais recente é instalar o pacote ELPA .

Kyle Meyer
fonte
Bem, eu não pode usar a versão de desenvolvimento, mas isso não significa que eu não tenha atualizado desde 2013. Eu não sou que tarde. ;)Para ser preciso, o meu org-versioné 8.2.10. Editei a pergunta com esta informação, onde deveria estar em primeiro lugar.
T. Verron 25/05
Opa, desculpe pela desinformação. Esse deve ser o commit, mas não está contido no 8.2.10.
Kyle Meyer
Você saberia onde posso encontrar uma discussão sobre esse commit?
T. Verron
Se existisse uma discussão sobre ela, provavelmente estaria na lista do modo Org, mas não encontrei uma pesquisando e não há uma referenciada na mensagem de confirmação, portanto, pode não haver uma.
Kyle Meyer