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))}
Related
This code is about inverting an index using clusters.
Unfortunately I do not understand the line with recognize<-...
I know that the function Vectorize applies the inner function element-wise, but I do not understand the inner function here.
The parameters (uniq, test) are not defined, how can we apply which then? Also why is there a "uniq" as text right after?
slots <- as.integer(Sys.getenv("NSLOTS"))
cl <- makeCluster(slots, type = "PSOCK")
inverted_index4<-function(x){
y <- unique(x)
recognize <- Vectorize(function(uniq,text) which(text %in% uniq),"uniq",SIMPLIFY = F)
y2 <- parLapply(cl, y, recognize, x)
unlist(y2,recursive=FALSE)
}
The
Vectorise()
function is just making a new element wise, vectorised function of the custom function
function(uniq,text) which(text %in% uniq).
The 'uniq' string is the argument of that function that you must specify you want to iterate over. Such that now you can pass a vector of length greater than one for uniq, and get returned a list with an element for the output of the function evaluated for every element of the input vector uniq.
I would suggest the author make the code a little clearer, better commented etc. the vectorise function doesn't need to be inside the function call necessarily.
Note
ParLapply()
isn't a function I recognise. But the x will be passed to the recognise function and the second argument text should presumably be defined earlier on, in the global environment, .GlobalEnv().
I have made a function that takes as an argument another function, the argument function takes as its argument some object (in the example a vector) which is supplied by the original function. It has been challenging to make the function call in the right way. Below are three approaches I have used after having read Programming with dplyr.
Only Option three works,
I would like to know if this is in fact the best way to evaluate a function within a function.
library(dplyr);library(rlang)
#Function that will be passed as an argument
EvaluateThis1 <- quo(mean(vector))
EvaluateThis2 <- ~mean(vector)
EvaluateThis3 <- quo(mean)
#First function that will recieve a function as an argument
MyFunc <- function(vector, TheFunction){
print(TheFunction)
eval_tidy(TheFunction)
}
#Second function that will recieve a function as an argument
MyFunc2 <- function(vector, TheFunction){
print(TheFunction)
quo(UQ(TheFunction)(vector)) %>%
eval_tidy
}
#Option 1
#This is evaluating vector in the global environment where
#EvaluateThis1 was captured
MyFunc(1:4, EvaluateThis1)
#Option 2
#I don't know what is going on here
MyFunc(1:4, EvaluateThis2)
MyFunc2(1:4, EvaluateThis2)
#Option 3
#I think this Unquotes the function splices in the argument then
#requotes before evaluating.
MyFunc2(1:4, EvaluateThis3)
My question is:
Is option 3 the best/most simple way to perform this evaluation
An explanation of what is happening
Edit
After reading #Rui Barradas very clear and concise answer I realised that I am actually trying to do someting similar to below which I didn't manage to make work using Rui's method but solved using environment setting
OtherStuff <-c(10, NA)
EvaluateThis4 <-quo(mean(c(vector,OtherStuff), na.rm = TRUE))
MyFunc3 <- function(vector, TheFunction){
#uses the captire environment which doesn't contain the object vector
print(get_env(TheFunction))
#Reset the enivronment of TheFunction to the current environment where vector exists
TheFunction<- set_env(TheFunction, get_env())
print(get_env(TheFunction))
print(TheFunction)
TheFunction %>%
eval_tidy
}
MyFunc3(1:4, EvaluateThis4)
The function is evaluated within the current environment not the capture environment. Because there is no object "OtherStuff" within that environment, the parent environments are searched finding "OtherStuff" in the Global environment.
I will try to answer to question 1.
I believe that the best and simpler way to perform this kind of evaluation is to do without any sort of fancy evaluation techniques. To call the function directly usually works. Using your example, try the following.
EvaluateThis4 <- mean # simple
MyFunc4 <- function(vector, TheFunction){
print(TheFunction)
TheFunction(vector) # just call it with the appropriate argument(s)
}
MyFunc4(1:4, EvaluateThis4)
function (x, ...)
UseMethod("mean")
<bytecode: 0x000000000489efb0>
<environment: namespace:base>
[1] 2.5
There are examples of this in base R. For instance approxfun and ecdf both return functions that you can use directly in your code to perform subsequent calculations. That's why I've defined EvaluateThis4 like that.
As for functions that use functions as arguments, there are the optimization ones, and, of course, *apply, byand ave.
As for question 2, I must admit to my complete ignorance.
I am trying to write a function and apply it to a list. Inside my function is a function written by some one else. If I make my list very easy, everything will work fine. But if I use all the real data I have, there are some bad objects and the outside function doesn't work and my whole function won't go through.
What do I type to say "If the outside function doesn't work, skip that object and move to the next one in the list."? With or without NA, doesn't matter.
I cannot figure out how to write a reproducible example that would result in a list of dataframes, which is what happens inside this function. I'm willing to take any help to improve this question.
My function is something like this:
do_this<- function(x){
outside_function(x))%>% #this returns a dataframe for each object
filter()%>%
select()%>%
summarise_each(funs(mean(., na.rm = TRUE))) #by the end the df is down to one row
}
This is how I apply the function to the list to come up with my final dataframe.
df<-bind_rows(lapply(my_list, do_this))
An example:
myfun <- function(x) {if (x == 1) {stop("bad")} else x}
throws error on input of 1:
lapply(1:4, myfun) # stops from error
Just wrap it in try (as long as you don't need more complex error handling):
L <- lapply(1:4, function(x) try(myfun(x)))
And then you can use Filter to get rid of the "bad" cases:
Filter(function(x) !inherits(x, "try-error"), L)
Although you may want to just make your wrapper function more robust, or return NULL (or some other appropriate value) under the condition that makes the inner function fail.
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.
In R, the idiomatic way to call another function without evaluating the parameters you give it is apparently as follows:
Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- as.name("name.of.function.to.be.called.here")
eval.parent(Call)
However, when I put a namespaced name (e.g. utils::write.csv) in the as.name() call, I get an error:
"could not find function "utils::write.csv"
What is the proper way of using this R idiom to call a namespaced function?
Here is a solution using do.call(), which both constructs and evaluates the function call.
Like the approach you started with, this one uses the fact that R calls are lists in which: (a) the first element is the name of a function; and (b) all following elements are arguments to that function.
j <- function(x, file) {
Call <- match.call(expand.dots = TRUE)
arglist <- as.list(Call)[-1]
do.call(utils::write.csv, arglist)
}
dat <- data.frame(x=1:10, y=rnorm(10))
j(dat, file="outfilename.csv")
EDIT: FWIW, here's an example from plot.formula in base R, which uses a construct similar to the one above:
{
m <- match.call(expand.dots = FALSE)
eframe <- parent.frame()
. . .
. . .
m <- as.list(m)
m[[1L]] <- stats::model.frame.default
m <- as.call(c(m, list(na.action = NULL)))
mf <- eval(m, eframe)
. . .
. . .
}
The function uses the do.call() construct later on. Going a bit deeper into the weeds, my reading is that in the snippet shown here, it instead uses several steps mostly because of the need to add na.action=NULL to the list of arguments.
In any case, it looks like the do.call() options is as close to canonical as could be desired.
As #Josh O'Brien answered, do.call is much more straight forward to use.
The first argument to do.call can be either a function name or an actual function.
The function name can NOT contain the namespace qualifier. The :: part is actually a function that takes the names on both sides and find the corresponding function, so it must be evaluated separately to work.
So, with do.call, you need something like:
# ...Stuff from Josh's answer goes here
# And then:
do.call(utils::write.csv, arglist)
And with eval:
Call <- match.call(expand.dots = TRUE)
# Modify parameters here as needed and set unneeded ones to NULL.
Call[[1L]] <- utils::write.csv
eval.parent(Call)
Note the lack of quotes around the function name. That evaluates to the function closure.
Another way of getting the function from a namespace-qualified name:
eval(parse(text="utils::write.csv"))
Again, the :: function is called that correctly finds the function.
Another more manual way is to extract the namespace name & function name and then do the lookup yourself:
x <- strsplit("utils::write.csv", "::")[[1]]
get(x[2], asNamespace(x[1]))