I did a test with nested return function in R, but without success. I came from Mathematica, where this code works well. Here is a toy code:
fstop <- function(x){
if(x>0) return(return("Positive Number"))
}
f <- function(x){
fstop(x)
"Negative or Zero Number"
}
If I evaluate f(1), I get:
[1] "Negative or Zero Number"
When I expected just:
[1] "Positive Number"
The question is: there is some non-standard evaluation I can do in fstop, so I can have just fstop result, without change f function?
PS: I know I can put the if direct inside f, but in my real case the structure is not so simple, and this structure would make my code simpler.
Going to stick my neck out and say...
No.
Making a function return not to its caller but to its caller's caller would involve changing its execution context. This is how things like return and other control-flow things are implemented in the source. See:
https://github.com/wch/r-source/blob/trunk/src/main/context.c
Now, I don't think R level code has access to execution contexts like this. Maybe you could write some C level code that could do it, but its not clear. You could always write a do_return_return function in the style of do_return in eval.c and build a custom version of R... Its not worth it.
So the answer is most likely "no".
I think Spacedman is right, but if you're willing to evaluate your expressions in a wrapper, then it is possible by leveraging the tryCatch mechanism to break out of the evaluation stack.
First, we need to define a special RETURN function:
RETURN <- function(x) {
cond <- simpleCondition("") # dummy message required
class(cond) <- c("specialReturn", class(cond))
attr(cond, "value") <- x
signalCondition(cond)
}
Then we re-write your functions to use our new RETURN:
f <- function(x) {
fstop(x)
"Negative or Zero"
}
fstop <- function(x) if(x > 0) RETURN("Positive Number") # Note `RETURN` not `return`
Finally, we need the wrapper function (wsr here stands for "with special return") to evaluate our expressions:
wsr <- function(x) {
tryCatch(
eval(substitute(x), envir=parent.frame()),
specialReturn=function(e) attr(e, "value")
) }
Then:
wsr(f(-5))
# [1] "Negative or Zero"
wsr(f(5))
# [1] "Positive Number"
Obviously this is a little hacky, but in day to day use would be not much different than evaluating expressions in with or calling code with source. One shortcoming is this will always return to the level you call wsr from.
Related
During my free time R studying, I read this article on usage of return(). In there, I came across a function, of which one element's meaning escapes my technical background, please see below:
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x)vector(length=x,mode="numeric"))(x),repeats)) }
I've played with the codes of the article, but the logic behind this tiny (x) (specifically, it's 2nd occurrence) in the 3rd line is unclear to me.
It's an anonymous function. If we unwrap the code
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x)
vector(length=x,mode="numeric")
)(x),
repeats)) }
we can see that within the rep( ... ) call, the first argument is
(function(x)vector(length=x,mode="numeric"))(x)
Now, this is a curious way of putting it. But what you get is that function(x) vector(...) defines a one-liner function (which calls vector to create a numeric vector of length x). Wrapped in parenthesis (function(x) ...) returns the function, and then with (function(x) ...)(x) calls the anonymous function with argument x.
You would get the same result from:
my_vector <- function(y) vector(length=y, mode="numeric")
bench_nor2 <- function(x, repeats) {system.time(rep(my_vector(x), repeats))}
Actual question
How can I mix standard and lazy evaluation of function arguments while giving the user a unified and simple syntax when calling my functions?
Background
I'm a huge fan of dplyr, but what I don't quite like about it is that it makes you use distinguish function names (e.g. select vs. select_) and that it makes you think too much of how to write function calls when you want to express your arguments as a "mixed bag": some are expressed as character strings, for others you want lazy evaluation, for yet others you want standard evaluation. Also see John Mount's blog post on wrapr for another example of where it becomes overly complex to do a simple thing due to standard vs. lazy evaluation.
Example
This is the simplest way of writing my dyplyr::select expression that I know of
x <- "disp"
select_(mtcars, "mpg", ~cyl, x)
After playing around, here's a draft of the solution I'm after:
select2 <- function(dat, ...) {
args <- substitute(list(...))
## Express names as character //
idx <- which(sapply(args, class) == "name")[-1]
## We don't care about the first one as it's going to be
## substituted anyway
if (length(idx)) {
for (ii in idx) args[[ii]] <- as.character(args[[ii]])
}
## Ensure `c()` //
args[[1]] <- quote(c)
## Standard eval for variables containing actual column name //
idx <- which(!eval(args) %in% names(dat)) + 1
if (length(idx)) {
for (ii in idx) args[[ii]] <- eval(as.name(args[[ii]]))
}
## Indexing expression //
exprsn <- substitute(dat[, J], list(J = eval(args)))
eval(exprsn)
}
x <- "disp"
(select2(mtcars, "mpg", cyl, x))
It works, but of course it's very poorly implemented with regard to efficiency ;-)
To make it better and to understand more with regard to evaluation in R, in particular I'd like to know how to get rid of the for loops and how I could best leverage existing functionality of the dplyr and lazyevalpackages as well as base-R functionality like do.call("[.data.frame", ...), with() or the like. Especially the indexing and assignment methods ("[.*" and "<-.*") and how to call them directly are still kind of a mystery for me.
I see there is another related question, but the answer isnt what I am looking for. I want a function that can be assigned to an object, but still will print the output even when assigned, but not double print it.
In this case:
fun <- function(x) {
print(x+1)
x+1
}
a <- fun(3)
In this case, it would both save to a, and it would print to console, which is what I want.
But in this case:
fun(3)
It would print to the console twice. Is there a way to get the desired result from case 1, without double printing on case 2?
Assuming that you still want your function to return the 'x+1' value, you could just wrap it in the invisible function:
fun <- function(x) {
print(x+1)
invisible(x+1)
}
> fun(3)
[1] 4
> a = fun(3)
[1] 4
> a
[1] 4
This will only print it out once, while still retaining the 'x+1' value.
You can accomplish this same behavior with any function in R that visibly returns an object by wrapping it in parentheses.
fun <- function(x) {
x+1
}
> (fun(3))
[1] 4
> (a = fun(3))
[1] 4
> a
[1] 4
Or, equivalently, you may simply call print on your assignment.
> print(fun(3))
[1] 4
I'm not sure rolling this functionality into a function has any benefits over using the existing print method outside of a function.
R functions shouldn't have unasked for "side effects". This isn't a rule, but a strong recommendation. As evidence for it being good practice, there are plenty of questions on SO like this one where a poorly behaved function prints output using print or cat that the end user struggles to disable.
Based on this, I would strongly encourage you to either use message() rather than print() or to add an argument that can disable the printing. message() is the "right" way print to the console during execution, but it won't format the result nicely depending on the data structure.
Thus, if your function expects simple outputs then I would recommend doing it like this:
fun <- function(x) {
result = x + 1
message(result)
invisible(result)
}
If it might have more complicated output, you could try something like this (demoing on mtcars):
fun <- function(x) {
result = head(mtcars)
sapply(capture.output(print(result)), message)
invisible(result)
}
Messages can easily be suppressed by wrapping the call in suppressMessages(), and message = F is a handy argument for knitr code chunks to say "ignore the messages".
The other option is to add an argument
fun <- function(x, quietly = FALSE) {
result = x + 1
if (!quietly) print(result)
invisible(result)
}
And I'd also think long and hard about whether this strange behavior is really necessary. Usually, having functions that behave as expected is better than having special cases that throw expectations.
I've been fascinated lately by Hadley Wickhams Non-standard Evaluation examples in R, but I'm not sure what I want to do is possible.
I want to have a closure-based environment where you pass expressions that get evaluated (in NSE ways), similar to how subset works. The problem though, is that to do so I think I need to fundamentally change how arguments are passed.
For example,
g <- function(setup_stuff){
function(x) {
substitute(x)
}
}
will give me the expression assigned to x if I so something like:
test <- g("Setup stuff")
test(1:10)
# 1:10
Similarly, I can do something like:
g <- function(setup_stuff){
function(x) {
sys.call(x)
}
}
Which will usually give me kind of what I'm looking for--a completely unevaluated argument list:
test <- g("setup variables")
test(1:10)
# test(1:10)
But this all relies on the idea that I pass variables the "standard" way, by delimiting assigned parameters with commas. I want to have something like:
g <- function(setup_stuff){
function(...) {
# Capture named expression(s) before evaluation
substitute(...)
}
}
Such that, for example, I can evaluate the arguments in a based on their named and the operators passed in, for example I've been trying to overload the logical operator &, but I just receive an error before the function to do NSE is even called:
test <- g("Setup stuff")
test(a=1 & b=2)
# > test(a=1 & b=2)
# Error: unexpected '=' in "test(a=1 & b="
I know I could probably do half-accomplish this by overloading the '&' and the '=' operator for some specific class, and just return the unevaluated call, but then a and b would need to be objects of that class, but I was wondering if I was missing something that someone can easily see?
The normal approach to writing functions in R (as I understand) is to avoid side-effects and return a value from a function.
contained <- function(x) {
x_squared <- x^2
return(x_squared)
}
In this case, the value computed from the input into the function is returned. But the variable x_squared is not available.
But if you need to violate this basic functional programming tenet (and I'm not sure how serious R is about this issue) and return an object from a function, you have two choices.
escape <- function(x){
x_squared <<- x^2
assign("x_times_x", x*x, envir = .GlobalEnv)
}
Both objects x_squared and x_times_x are returned. Is one method preferable to the other and why so?
Thomas Lumley answers this in a superb post on r-help the other day. <<- is about the enclosing environment so you can do thing like this (and again, I quote his post from April 22 in this thread):
make.accumulator<-function(){
a <- 0
function(x) {
a <<- a + x
a
}
}
> f<-make.accumulator()
> f(1)
[1] 1
> f(1)
[1] 2
> f(11)
[1] 13
> f(11)
[1] 24
This is a legitimate use of <<- as "super-assignment" with lexical scope. And not simply to assign in the global environment. For that, Thomas has these choice words:
The Evil and Wrong use is to modify
variables in the global environment.
Very good advice.
According to the manual page here,
The operators <<- and ->> cause a search to made through the environment for an existing definition of the variable being assigned.
I've never had to do this in practice, but to my mind, assign wins a lot of points for specifying the environment exactly, without even having to think about R's scoping rules. The <<- performs a search through environments and is therefore a little bit harder to interpret.
EDIT: In deference to #Dirk and #Hadley, it sounds like assign is the appropriate way to actually assign to the global environment (when that's what you know you want), while <<- is the appropriate way to "bump up" to a broader scope.
As pointed out by #John in his answer, assign lets you specify the environment specifically. A specific application would be in the following:
testfn <- function(x){
x_squared <- NULL
escape <- function(x){
x_squared <<- x^2
assign("x_times_x", x*x, envir = parent.frame(n = 1))
}
escape(x)
print(x_squared)
print(x_times_x)
}
where we use both <<- and assign. Notice that if you want to use <<- to assign to the environment of the top level function, you need to declare/initialise the variable. However, with assign you can use parent.frame(1) to specify the encapsulating environment.