Confusion about function arguments in R

If I declare a function, I can refer to the previous arguments:

blah <- function( a=1, b=a ) { print(sprintf("a=%d, b=%d", a, b)) }

      

Output:

> blah(10)
[1] "a=10, b=10"
> blah(10, b=30)
[1] "a=10, b=30"

      

However, the following doesn't work:

> blah(a=10, b=a)
Error in sprintf("a=%d, b=%d", a, b) : object 'a' not found

      

Actually, this is more or less what one might expect; so why is the ad blah <- function(a=10, b=a)

working? Why is the scope different here than when I call the function?

Also why does the error only appear when called sprintf

? Why doesn't it throw an error right away when the function is called? I'm confused.

Edit:

Here I will explain my confusion. When I declare a function, the parameters are not evaluated. R is lazy and the variables are evaluated as needed. Consider this:

> blah <- function( a=1, b=print("foo") ) { print( "So far, so good") ; print( b )  }
>

      

There was no assessment. I now call blah:

> blah()
[1] "So far, so good"
[1] "foo"
[1] "foo"

      

The first operator in the function is evaluated, then print("foo")

. However, at that time, and there is - we have this in the area of ​​functions. So why b=a

not rate it? We are already in the function when this happens and it was declared.

Edit 2:

Before jumping to the wrong conclusions, please note that referring to the previous argument is fine fine in the function declaration in R due to R's lazy evaluation.I don't understand why it works in the function declaration, but not when I call. I'm not saying this should or shouldn't work, just wondering about the underlying review mechanics.

+3


source to share


2 answers


There is a difference between where the two expressions are evaluated. When you call the function, the parameters are evaluated in the current scope. When you define a function, the parameters are evaluated within the scope. This is usually the behavior you want.

Therefore, when you call a function, it expects you to control all the values ​​passed to the function. You don't need to know what variables are used inside the function. With lazy evaluation, this construct also works:

blah <- function( a=1, b=x ) {
   x < a+10
   print(sprintf("a=%d, b=%d", a, b))
}
blah(1)

      

so try calling

blah(1, b=x+5)

      



makes even less sense, because technically you don't even have to know the variable x

inside the function.

In this example, you can see the difference in the environments. Here we use parent.frame()

to get the environment from which the function was called.

myenv <- function() parent.frame()
foo <- function( a=myenv() ) {
    print(environment())
    print(a)
}
foo()
# <environment: 0x10c8b1948>
# <environment: 0x10c8b1948>
foo( a=myenv() )
# <environment: 0x10bd85ad8>
# <environment: R_GlobalEnv>

      

So, when a function runs with a default value, it runs in the same environment as the function itself. When you pass a parameter explicitly, it runs in the environment when it was called (which in this case is the global environment).

This means that you cannot use function parameter names as variables while setting other parameter values ​​when calling the function.

+2


source


When you do:

> blah(a=10, b=a)

      

You say: I have a value 10

in my global envrionment and I am assigning it to the argument a

. I have a variable a

in my global environment and I assign its value to an argument b

. A variable is a

completely different from a a

function argument ! If a variable a

is undefined and you want to pass it to a function, shout R

.



You will have the same error:

 > blah(a=10, b=nonExistingVariable)
 Error in sprintf("a=%d, b=%d", a, b) : object 'NonExistingVariable' not found

      

+2


source







All Articles