promessa já em avaliação: referência recursiva ao argumento padrão ou problemas anteriores?


143

Aqui está o meu código R. As funções são definidas como:

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}

g <- function(x, T, f=f) {
  exp(-f(x) / T)
}

test <- function(g=g, T=1) { 
  g(1, T)
}

O erro de execução é:

> test ()
Erro no teste ():
promessa já em avaliação: referência de argumento padrão recursivo ou problemas anteriores?

Se eu substituir a definição fde g, então o erro desaparece.

Eu queria saber qual foi o erro? Como corrigi-lo se não substituir a definição de fna de g? Obrigado!


Atualizar:

Obrigado! Duas questões:

(1) se a função testseguir um argumento f, você adicionará algo como test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) }? Nos casos com mais recursões, é uma prática boa e segura adicionar mais . ?

(2) se fé um argumento não funcional, por exemplo , g <- function(x, T, f=f){ exp(-f*x/T) }e test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }usará o mesmo nome para argumentos não funcionais formais e reais uma prática boa e segura ou pode causar algum problema em potencial?

Respostas:


159

Argumentos formais do formulário x=xcausam isso. Eliminando as duas instâncias em que ocorrem, obtemos:

f <- function(x, T) {
   10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}

g <- function(x, T, f. = f) {  ## 1. note f.
   exp(-f.(x)/T) 
}

test<- function(g. = g, T = 1) {  ## 2. note g.
   g.(1,T) 
}

test()
## [1] 8.560335e-37

2
Obrigado! Duas perguntas (1) se o teste de função continuar com um argumento para f , você adicionará algo como função <<(g. = G, T = 1, f .. = f) {g. (1, T, f. = f ..)} ? Nos casos com mais recursões, é uma prática boa e segura adicionar mais . ? (2) se f é um argumento não funcional, por exemplo, g <- função (x, T, f = f) {exp (-f x / T)} * e teste <- função (g. = G, T = 1, f = f) {g. (1, T, f = f.)} , Usará o mesmo nome para argumentos não funcionais formais e reais uma prática boa e segura ou poderá causar algum problema em potencial?
Tim

16
Alguma outra solução? Estou passando alguns argumentos bem no fundo da cadeia de funções (cerca de 5 níveis), e essa solução pode se tornar .....cumbersome. :)
Roman Luštrik

2
@ RomanLuštrik Se você está passando os argumentos para baixo e pode ignorá-los com segurança, use elipses ...ou uma lista para passar os argumentos pela cadeia de funções. É muito mais flexível (para o bem e para o mal) do que pré-definir tudo. Você pode acabar precisando adicionar algumas verificações para garantir que seus argumentos originais nas elipses (ou na lista) sejam sensatos.
precisa saber é o seguinte

2
Outra opção aqui é tentar explicitamente encontrar os argumentos em um quadro pai, ignorando o forçamento acidental da promessa ativa - por exemplo get("f", envir = parent.frame()).
Kevin Ushey

1
O único requisito é que você não use o mesmo nome no lado esquerdo e no lado direito. Fora isso, é apenas estilo.
G. Grothendieck

13

Se você especificar o contexto de avaliação do argumento, evita o problema do mesmo nome:

f <- function(x) {
  10 * sin(0.3 * x) * sin(1.3 * x ^ 2) + 0.001 * x ^ 3 + 0.2 * x + 80
}
g <- function(x, t=1, f=parent.frame()$f) {
  exp(-f(x) / t)
}
test <- function(g=parent.frame()$g, t=1) { 
  g(1,t)
}
test()
[1] 8.560335e-37

2
Esta é uma maneira melhor, eu acho especificar o ambiente é mais clara
cloudscomputes

1

Eu gosto da resposta G. Grothendieck , mas fiquei imaginando que, no seu caso, é mais simples não incluir nomes de funções nos parâmetros das funções, como este:

f <- function(x, T) {
  10 * sin(0.3 * x) * sin(1.3 * x^2) + 0.001 * x^3 + 0.2 * x + 80 
}
g <- function(x, T) {
  exp(-f(x)/T) 
}
test<- function(T = 1) {
  g(1,T)
}
test()
## [1] 8.560335e-37

1

Como já mencionado, o problema vem de ter um argumento de função definido como ele mesmo. No entanto, quero adicionar uma explicação de por que isso é um problema, porque o entendimento me levou a uma maneira mais fácil (para mim) de evitar o problema: basta especificar o argumento na chamada em vez da definição.

Isso não funciona:

x = 4
my.function <- function(x = x){} 
my.function() # recursive error!

mas isso funciona:

x = 4
my.function <- function(x){} 
my.function(x = x) # works fine!

Os argumentos da função existem em seu próprio ambiente local.

R procura variáveis ​​primeiro no ambiente local, depois no ambiente global. É exatamente como em uma função uma variável pode ter o mesmo nome que uma variável no ambiente global e R usará a definição local.

Ter definições de argumento de função em seu próprio ambiente local é o motivo pelo qual você pode ter valores de argumento padrão com base em outros valores de argumento, como

my.function <- function(x, two.x = 2 * x){}

Portanto, é por isso que você não pode DEFINIR uma função, my.function <- function(x = x){}mas pode CHAMAR a função usando my.function(x = x). Quando você define a função, R fica confuso porque encontra o argumento x =como o valor local de x, mas quando você chama a função que R encontra x = 4no ambiente local de onde está chamando.

Portanto, além de corrigir o erro alterando o nome do argumento ou especificando explicitamente o ambiente, conforme mencionado em outras respostas, você também pode especificar isso x=xao chamar a função em vez de defini-la. Para mim, especificar que x=xa chamada era a melhor solução, pois não envolve sintaxe extra ou acumula cada vez mais nomes de variáveis.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.