Question

If we call a function directly in R, lazy evaluation takes place, so that the function arguments are not evaluated until they are encountered in the function body. An effect of this is that using match.call() at the beginning of a function, say a model fitter like lm, captures the call with unevaluated function arguments. Thus, the call to the function can be retrieved with promises instead of evaluated arguments by executing the model fitting function. The disadvantage of this is that the function has to be executed before the call with unevaluated arguments can be obtained.

R's call function, on the other hand, can be used to create an unevaluated call to a model fitting function, but the specified arguments are evaluated. What I would like to do is to create an object that is an unevaluated call to a function in which the function arguments are also unevaluated. A rather trivial example (pretend that the arg1 + arg2-part is something which is computationally expensive):

Foo <- function(arg1, arg2){
 mycall <- match.call()
 value <- arg1 + arg2
 list(value = value,
      call = mycall)
}

x <- 1
y <- 2

# calling Foo directly
test1 <- Foo(x,y)
test1   # the call with unevaluated arguments is now accessible, but the 
        # computations in Foo had to be performed as well.

# now via 'call'
Foocall <- call("Foo", arg1 = x, arg2 = y)
test2 <- eval(Foocall)
test2
Foocall # Foocall is an unevaluated call to Foo, but arg1 and arg2 in 
        # Foocall are no longer promises.   

What I want is something like:

Foocall <- call("Foo", arg1 = x, arg2 = y, eval.dots = FALSE)

yielding

 # not run 
 > Foocall
 > Foo(arg1 = x, arg2 = y)

Is there an easy solution to my problem?

Was it helpful?

Solution

Wrapping each supplied argument with a call to quote() will accomplish what you seem to be asking for:

Foocall <- call("Foo", arg1=quote(x), arg2=quote(y))

## Check that it works
Foocall
# Foo(arg1 = x, arg2 = y)

eval(Foocall)
# $value
# [1] 3
# 
# $call
# Foo(arg1 = x, arg2 = y)

identical(Foocall, eval(Foocall)$call)
# [1] TRUE

If you'd further like to be able to supply unnamed arguments and have them automatically matched by position to their associated formal arguments, just wrap the preceding in a call to match.call():

## Note that arg1 and arg2 not explicitly mentioned anywhere in this call
match.call(Foo, call("Foo", quote(x), quote(y))) 
# Foo(arg1 = x, arg2 = y)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top