tags:

views:

153

answers:

1

I've been trying to learn more about R (and writing C extensions) and I thought it might help to read the source for some well known packages. I decided to start with rpart which is defined as:

rpart <- function(formula, data, weights, subset,
    na.action=na.rpart, method, model=FALSE, x=FALSE, y=TRUE,
    parms, control, cost, ...)

I did a quick search through the source and I don't see formula mentioned anywhere in the function body yet I know that somehow rpart is using that parameter. How is it that rpart is using formula without its name being in the function body?

+4  A: 

It's pretty tricky:

m <- match.call(expand.dots = FALSE)
# ...
m[[1L]] <- as.name("model.frame")
m <- eval(m, parent.frame())

The function uses match.call to find out how it is being called, modifies the call to replace the called function by model.frame, and calls it via eval with the parameters it received (although the part I replaced by # ... removes several of the parameters), and model.frame uses the formula parameter. See the documentation of match.call, eval, and model.frame, and experiment a little, e.g. try to understand what is happening here:

> f <- function(formula, data) { 
+   m <- match.call()
+   m[[1L]] <- as.name('model.frame')
+   eval(m, parent.frame())
+ }
> f(x ~ y)
Error in eval(expr, envir, enclos) : object 'x' not found
> x <- c(1,2,3)
> f(x ~ y)
Error in eval(expr, envir, enclos) : object 'y' not found
> y <- c(3,4,5)
> f(x ~ y)
  x y
1 1 3
2 2 4
3 3 5
> d <- as.data.frame(matrix(c(1,2,3,4),nrow=2))
> names(d) <- c('foo', 'bar')
> f(foo ~ bar, d)
  foo bar
1   1   3
2   2   4
Jouni K. Seppänen