Matifou
Matifou

Reputation: 8880

R using the ellipsis ... in a call()

I am trying to write a custom curve function where the ... would be passed to the function rather than the plot: I would like to be able to use say:

curve2(dnorm, mean=2, sd=3)

I run into a problem with handling the ... in a call environment. Starting from a simplified prototype of curve:

minicurve <- function (expr, from = 0, to = 1, ...) 
{
sexpr <- substitute(expr)
expr <- call(as.character(sexpr), as.name("x")) 
  ll <- list(x = seq(from=from, to=to, length.out=100))
  names(ll) <- "x"
  y <- eval(expr, envir = ll, enclos = parent.frame())
  plot(x = ll$x, y = y, type="l")
}

# This gives the same behaviour as `curve`:
minicurve(dnorm)

Now I would like to pass the ... into the call (instead of passing into plot). Usually, this is very easy, one just need to pass the ... into the function. However, the call function behaves differently, and I am not sure how I should handle it. I can just use:

 dot1 <- substitute(...)
 expr <- call(as.character(sexpr), as.name(xname), dot1) 

This will work, however it will pass only the first argument. I need hence to use someting like:

 dots <- substitute(list(...))
 expr <- call(as.character(sexpr), as.name(xname), dots) 

But this doesn't work:

minicurve2 <- function (expr, from = 0, to = 1, ...) 
{
 sexpr <- substitute(expr)
 dots <- substitute(list(...))
 expr <- call(as.character(sexpr), as.name(xname), dots) 
 ll <- list(x = seq(from=from, to=to, length.out=100))
 names(ll) <- "x"
 y <- eval(expr, envir = ll, enclos = parent.frame())
 plot(x = ll$x, y = y, type="l")
}

So how do I pass a list of ... into the call function? Thanks!

Upvotes: 5

Views: 523

Answers (1)

MrFlick
MrFlick

Reputation: 206167

How about this

minicurve <- function (expr, from = 0, to = 1, ...) {
    sexpr <- substitute(expr)
    expr <- call(as.character(sexpr), as.name("x")) 
    ll <- list(x = seq(from=from, to=to, length.out=100))
    names(ll) <- "x"

    dots <- substitute(...())
    expr <- as.call(c(as.list(expr), dots))

    y <- eval(expr, envir = ll, enclos = parent.frame())
    plot(x = ll$x, y = y, type="l")
}

Here we capture the ... as a list via the substitute(...()) syntax. Then we convert the call to a list, append in the parameters, and turn it back into a call.

We test with

minicurve(dnorm, mean=2, sd=3)

mean 2

minicurve(dnorm, mean=.5, sd=5)

mean .5

Upvotes: 5

Related Questions