简体   繁体   中英

Evaluating a function that is an argument in another function using quo() in R

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:

  1. Is option 3 the best/most simple way to perform this evaluation
  2. 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 , by and ave .

As for question 2, I must admit to my complete ignorance.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM