Due to a typo I found out this code works [note the repeated - in the 2nd line]
foo <- function()
-------------------------
{
1
}
Calling foo() returns -1. The number of - determines if the returned value is positive or negative [odd number returns a negative number].
I didn't find anything regarding this R function definition so I am now asking why is this allowed and what is the purpose of this.
Even the official R documentation doesn't mention this at all. Any idea?
A note: invisible(1) doesn't work. The output is not suppressed when there is a sign character before the opening {.
You've tripped on the strange allowances of R's syntax rules for function bodies.
Since the syntax of functions in R allow for any expression after the argument list, usually R functions provide a list of expressions surrounded by {}. This is sometimes known in other languages as an expression "block." In R, the "evaluation value" of a block is the evaluation value of the last expression in the block.
If -1 is a valid expression, then -{1} is a valid expression as well.
- is also the unary negation operator, and it is repeatable in R. Therefore:
1 = 1
-1 != -1
--1 == 1
----1 == 1
-----1 == -1
So the evaluation goes:
foo <- function() ------------------------- {1}
foo <- function() ------------------------- 1
foo <- function() -1
And due to R's syntax rules, you could as easily go:
foo <- function() -1
Related
Consider the following R input:
if(TRUE){1}else{0} + if(TRUE){1}else{0}
The result is 1, but I was expecting 2. If I enclose each if-else statement in parentheses,
(if(TRUE){1}else{0}) + (if(TRUE){1}else{0})
then the result is 2.
Can someone explain this behaviour?
The else clause doesn't end till R can identify the end of the expression. In R the {} aren't part of the syntax for if/else statements. The {} can be used anywhere you want to possibly put multiple statements. You can also do
if(TRUE) 1 else 0 + if(TRUE) 1 else 0
The {} aren't really meaningful. And since
0 + if(TRUE) 1 else 0
is a valid expression, R just assumes you wanted all of that for your else clause. Normally R will end the else clause when it encounters a newline after a completed expression. This means that
if(TRUE){1}else{0} +
if(TRUE){1}else{0}
will also return the same value because the + at the end of the first line indicates that there's more to come because a valid expression can't end in +.
Note you can see how the expression is turned into the abstract syntax tree with the help of the lobstr package if you are really curious.
#lobstr::ast(if(TRUE){1}else{0} + if(TRUE){1}else{0})
o-`if`
+-TRUE
+-o-`{`
| \-1
\-o-`+`
+-o-`{`
| \-0
\-o-`if`
+-TRUE
+-o-`{`
| \-1
\-o-`{`
\-0
Here we see that everything is nested in the first if. The + is not the main operator.
As you've done, you can use () or {} to end the expression blocks explicitly
{if(TRUE){1}else{0}} + {if(TRUE){1}else{0}}
Consider also the case of
x <- 5
if(FALSE) x+1 else x+2
# [1] 7
if(FALSE) x+1 else {x}+{2}
# [1] 7
Note how the x+2 is taken all together for the else expression. It doesn't end at the first symbol x.
Is has something to to with operator affinity which determines the order of evaluation. Like math, parenthesis have a higher priority than multiplications with have a higher priority than plus and minus. The second part of the expression will never get evaluated and thus ignored resulting in 1 e.g. if(TRUE){1}else{0} + message("I'll never get printed"). Including the parenthesis will force to first evaluate both parts seperatley and then do the plus resulting in 2.
I'm trying to use possibly() to print the argument x as a message when the function sum() fails.
library(purrr)
t <- function(x) {
p <- possibly(sum, otherwise = message(x))
p(x)
}
However, I would not expect the below to retrieve any message, since sum() doesn't fail:
> t(1)
1
[1] 1
Instead, the script below works as expected: sum() fails, thus t() prints the message 'a'
> t('a')
a
NULL
As noted in the other answer, possibly simply does something quite different from what you want.
What you want is tryCatch (part of base R):
t <- function(x) {
tryCatch(sum(x), error = function (.) message(x))
}
t(1)
# [1] 1
t('a')
# a
The argument otherwise of the function purrr::possibly is a value but message(x) is an R expression. According to the documentation:
These functions wrap functions so that instead of generating side effects through printed output, messages, warnings, and errors, they return enhanced output.
One of the most important things to know about the evaluation of arguments to a function is that supplied arguments and default arguments are treated differently. The supplied arguments to a function are evaluated in the evaluation frame of the calling function. The default arguments to a function are evaluated in the evaluation frame of the function.
I don't quite understand what it is meant by calling function. Is it the function that is invoked (like in interactive sesion with function that has named assigned you type name and hit enter). If yes how evaluation frame of the callinig function differs from evaluation frame of the function?
First change to standard terms. The arguments that are used in the function definition are the formal arguments and the arguments that are passed to the function when calling it are the actual arguments. (The quoted passage in the question is referring to the actual arguments when it uses the nonstandard term, supplied arguments.)
Consider two cases via example.
Case 1
Below f has the formal argument x and when f is called in the last line of code there are no actual arguments.
Now when f is called in the last line of code x gets the value 2 because x is not set until it is used and when it is used a is looked up within the function where it has the value 2, not in the caller where it has the value 1.
a <- 1
f <- function(x = a) {
a <- 2
x
}
f()
## [1] 2
Case 2
On the other hand the actual arguments are evaluated in the caller. In the last line of code below x is set to 1 because that is the value of b in the caller. Again, x is not evaluated until it is used but now even though b has been set to 2 in the function itself this has no effect on x. x is set to 1, not 2.
b <- 1
g <- function(x) { b <- 2; x + b }
g(b)
## [1] 3
Other
Although this covers the two cases in the quote note that there exists another case which is the situation that occurs when x is referred to in a function but is not defined in the function. In the code below a is a free variable in g since a is not an argument or otherwise defined in g. In this case when gg (which equals g) is called R attempts to look up a in the function g and fails but the next place it looks is not the caller (where a is 1) but the environment in which the function was defined, i.e. the environment where the word function appears and a is 2 in that environment.
a <- 1
f <- function() {
a <- 2
g <- function() a
}
gg <- f()
gg()
## [1] 2
This is referred to as lexical scoping since one can tell where the free variables are looked up by simply looking at the function definitions.
I would like to print the element number of the list that is going through a function. For example if there are 10 elements in the list, I would like a counter that will go from 0-10 as the function goes through each element.
a = length(url)
func0 = function(url){
a = a-1
print(a)
}
cc = lapply(url, func0)
However this does not work. Please let me know what I'm doing wrong.
Your function changes the internal copy of variable a, and prints number 9 10 times. To change this behaviour to desired you should change the assignment operator = (btw, why not <-? equal sign is usually used in definitions of functions' parameters) to the global assignment operator <<-.
func0 = function(url){
a <<- a-1
print(a)
}
It will work, but the common recommendation is to avoid the global assignment operator in your code.
As an alternative I can suggest to check the package pbapply, which adds progress bar to the *apply functions.
require(pbapply)
pblapply(url, func1)
Where func1 will stand for the the function you want to apply to each element of the list.
Consider the following simple function:
f <- function(x, value){print(x);print(substitute(value))}
Argument x will eventually be evaluated by print, but value never will. So we can get results like this:
> f(a, a)
Error in print(x) : object 'a' not found
> f(3, a)
[1] 3
a
> f(1+1, 1+1)
[1] 2
1 + 1
> f(1+1, 1+"one")
[1] 2
1 + "one"
Everything as expected.
Now consider the same function body in a replacement function:
'g<-' <- function(x, value){print(x);print(substitute(value))}
(the single quotes should be fancy quotes)
Let's try it:
> x <- 3
> g(x) <- 4
[1] 3
[1] 4
Nothing unusual so far...
> g(x) <- a
Error: object 'a' not found
This is unexpected. Name a should be printed as a language object.
> g(x) <- 1+1
[1] 4
1 + 1
This is ok, as x's former value is 4. Notice the expression passed unevaluated.
The final test:
> g(x) <- 1+"one"
Error in 1 + "one" : non-numeric argument to binary operator
Wait a minute... Why did it try to evaluate this expression?
Well the question is: bug or feature? What is going on here? I hope some guru users will shed some light about promises and lazy evaluation on R. Or we may just conclude it's a bug.
We can reduce the problem to a slightly simpler example:
g <- function(x, value)
'g<-' <- function(x, value) x
x <- 3
# Works
g(x, a)
`g<-`(x, a)
# Fails
g(x) <- a
This suggests that R is doing something special when evaluating a replacement function: I suspect it evaluates all arguments. I'm not sure why, but the comments in the C code (https://github.com/wch/r-source/blob/trunk/src/main/eval.c#L1656 and https://github.com/wch/r-source/blob/trunk/src/main/eval.c#L1181) suggest it may be to make sure other intermediate variables are not accidentally modified.
Luke Tierney has a long comment about the drawbacks of the current approach, and illustrates some of the more complicated ways replacement functions can be used:
There are two issues with the approach here:
A complex assignment within a complex assignment, like
f(x, y[] <- 1) <- 3, can cause the value temporary
variable for the outer assignment to be overwritten and
then removed by the inner one. This could be addressed by
using multiple temporaries or using a promise for this
variable as is done for the RHS. Printing of the
replacement function call in error messages might then need
to be adjusted.
With assignments of the form f(g(x, z), y) <- w the value
of z will be computed twice, once for a call to g(x, z)
and once for the call to the replacement function g<-. It
might be possible to address this by using promises.
Using more temporaries would not work as it would mess up
replacement functions that use substitute and/or
nonstandard evaluation (and there are packages that do
that -- igraph is one).
I think the key may be found in this comment beginning at line 1682 of "eval.c" (and immediately followed by the evaluation of the assignment operation's RHS):
/* It's important that the rhs get evaluated first because
assignment is right associative i.e. a <- b <- c is parsed as
a <- (b <- c). */
PROTECT(saverhs = rhs = eval(CADR(args), rho));
We expect that if we do g(x) <- a <- b <- 4 + 5, both a and b will be assigned the value 9; this is in fact what happens.
Apparently, the way that R ensures this consistent behavior is to always evaluate the RHS of an assignment first, before carrying out the rest of the assignment. If that evaluation fails (as when you try something like g(x) <- 1 + "a"), an error is thrown and no assignment takes place.
I'm going to go out on a limb here, so please, folks with more knowledge feel free to comment/edit.
Note that when you run
'g<-' <- function(x, value){print(x);print(substitute(value))}
x <- 1
g(x) <- 5
a side effect is that 5 is assigned to x. Hence, both must be evaluated. But if you then run
'g<-'(x,10)
both the values of x and 10 are printed, but the value of x remains the same.
Speculation:
So the parser is distinguishing between whether you call g<- in the course of making an actual assignment, and when you simply call g<- directly.