promise already under evaluation: recursive default argument reference or earlier problems?

R

R Problem Overview


Here is my R code. The functions are defined as:

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)
}

The running error is:

> > test()
> Error in test() :
> promise already under evaluation: recursive default argument reference or earlier problems?

If I substitute the definition of f in that of g, then the error goes away.

I was wondering what the error was? How to correct it if don't substitute the definition of f in that of g? Thanks!


Update:

Thanks! Two questions:

(1) if function test further takes an argument for f, will you add something like test <- function(g.=g, T=1, f..=f){ g.(1,T, f.=f..) } ? In cases with more recursions, is it a good and safe practice adding more .?

(2) if f is a non-function argument, for example g <- function(x, T, f=f){ exp(-f*x/T) } and test <- function(g.=g, T=1, f=f){ g.(1,T, f=f.) }, will using the same name for both formal and actual non-functional arguments a good and safe practice or it may cause some potential trouble?

R Solutions


Solution 1 - R

Formal arguments of the form x=x cause this. Eliminating the two instances where they occur we get the following. (The reason you can't use x=x in the formal arguments of a function definition is that it first looks up the default argument within the function itself so using that form is telling it to use itself as the default but it has not been defined so that makes no sense and we get an error.)

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

Solution 2 - R

If you especify argument evaluation context, you avoid the problem of same name:

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

Solution 3 - R

As already mentioned, the problem comes from having a function argument defined as itself. However, I want to add an explanation of why this is a problem because understanding that led me to an easier (for me) way to avoid the problem: just specify the argument in the call instead of the definition.

This does not work:

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

but this does work:

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


Function arguments exist in their own local environment.

R looks for variables first in the local environment, then in the global environment. This is just like how inside a function a variable can have the same name as a variable in the global environment, and R will use the local definition.

Having function argument definitions form their own local environment is why you can have default argument values based on other argument values, like

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

So this is why you cannot DEFINE a function as my.function <- function(x = x){} but you can CALL the function using my.function(x = x). When you define the function, R gets confused because it finds the argument x = as the local value of x, but when you call the function R finds x = 4 in the local environment you are calling from.

So in addition to fixing the error by changing the argument name or explicitly specifying the environment as mentioned in other answers, you can also just specify that x=x when you call the function instead of when you define it. For me, specifying that x=x in the call was the best solution, since it does not involve extra syntax or accumulating more and more variable names.

Solution 4 - R

I like the G. Grothendieck answer, but I was wondering that is more simple in your case to not include function names in the parameters of functions, like this:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTimView Question on Stackoverflow
Solution 1 - RG. GrothendieckView Answer on Stackoverflow
Solution 2 - Rxm1View Answer on Stackoverflow
Solution 3 - RrrrView Answer on Stackoverflow
Solution 4 - Rt4x0nView Answer on Stackoverflow