4

How can I tell R to use the default value of a function argument without i) omitting the argument in the function call and ii) without knowing what the default value is?

I know I can use the default value of mean in rnorm():

rnorm(n = 100) # by omitting the argument
# or
rnorm(n = 100, mean = 0) # by including it in the call with the default value

But assume I don't know the default value but want to include it explicitly in the function call. How can I achieve that?

D Pinto
  • 871
  • 9
  • 27

2 Answers2

5

You can access the argument list and default values via:

> formals(rnorm)
$n


$mean
[1] 0

$sd
[1] 1

formals("rnorm") also works. Some simple examples:

> rnorm(10,mean = formals(rnorm)$mean)
 [1] -0.5376897  0.4372421  0.3449424 -0.9569394 -1.1459726 -0.6109554  0.1907090  0.2991381 -0.2713715
[10] -1.4462570
> rnorm(10,mean = formals(rnorm)$mean + 3)
 [1] 2.701544 2.863189 1.709289 2.987687 2.848045 5.136735 2.559616 3.827967 3.079658 5.016970

Obviously, you could store the result of formals(rnorm) ahead of time as well.

joran
  • 169,992
  • 32
  • 429
  • 468
1

As @joran has already pointed out, formals() exposes the default values. However, as I understand the question, what you're really after is the construction of the call expression. To that end, it is useful to combine formals() with as.call() to produce the call itself. The following function does just that, by producing a function that produces "argument-completed calls," for a given function name f:

drop_missing <- function(sig) {
  sig[!sapply(sig, identical, quote(expr =))]
}

complete_call <- function(f) {
  nm <- as.name(f)
  sig <- formals(args(f))
  make_call <- function() {
    args <- match.call()[-1]
    sig[names(args)] <- args
    as.call(c(nm, drop_missing(sig)))
  }
  formals(make_call) <- sig
  make_call
}

Example usage:

complete_call("log")(1)
#> log(x = 1, base = exp(1))

complete_call("rnorm")(10)
#> rnorm(n = 10, mean = 0, sd = 1)

complete_call("rnorm")()
#> rnorm(mean = 0, sd = 1)

Remarks:

1) The output is a language object. To execute the call, you need to evaluate it, e.g.,

eval(complete_call("rnorm")(10))
#> [1] -0.89428324 -1.78405483 -1.83972728 ... (output truncated)

2) If you want complete_call() to accept a function, rather than the name of a function, you could write nm <- as.name(deparse(substitute(f))) in place of the given assignment. However, that would not work in a nested call, where you would get as.name("f") for nm, because of R's rules fo lexical scoping.

3) Without the call to args() in the assignment of sig, complete_call() would only work for closures, since primitive and builtin functions don't have formals.

egnha
  • 1,157
  • 14
  • 22