AdrienF
AdrienF

Reputation: 978

Using match.call() with mapply

I have a function that basically outputs a boolean condition as a string from the arguments (the details of the function don't matter here)

makeClause <-function(Sex=c("NA", "male", "female"),
        SmokingHx=c("NA", "current", "former", "never"),
        conjunction=c("&", "|")) {
    arglist = as.list(match.call())
    return(arglist)
}

I have a data frame that has all combinations of input arguments, as:

       Sex SmokingHx conjunction
1       NA        NA           &
2     Male        NA           &
...

Which I obtain this way:

combinations = expand.grid(Sex=c("NA", "male", "female"), 
                           SmokingHx=c("NA", "current", "former", "never"), 
                           conjunction=c("&", "|"),
                           stringsAsFactors=FALSE)

And I call makeClause with mapply:

mapply(makeClause, Sex=combinations$Sex,SmokingHx=combinations$SmokingHx, conjunction=combinations$conjunction)

Looking at the arglist variable I get:

$Sex
dots[[1L]][[1L]]

$SmokingHx
dots[[2L]][[1L]]

$conjunction
dots[[4L]][[1L]]

And if instead of as.list(match.call()) I call as.list(environment()) I get instead:

$Sex
[1] "male"

$SmokingHx
[1] "NA"

$conjunction
dots[[4L]][[1L]] # notice this is the only one for which I don't get the actual string

So I have two questions:

  1. Could you explain the R internals that lead to getting this as argument values instead of the actual string values ?
  2. How can I remedy this, i.e. get the string values in the argument list?

Thanks

Upvotes: 3

Views: 253

Answers (1)

BrodieG
BrodieG

Reputation: 52637

Why This is Happening:

match.call captures the quoted call as a language object. The dots business is what mapply is using to invoke your function, so the return value of match.call is correct. It is just matching the call that mapply constructed for your function and returning the quoted (i.e. unevaluated) values. Internally mapply is doing something like this (though not really since it is internal C code):

dots <- list(...)
call <- list()
for(j in seq_along(dots[[1]])) {
  for(i in seq_along(dots)) call[[i]] <- bquote(dots[[.(j)]][[.(i)]])
  eval(as.call(c(quote(FUN), call))))
}

If you look at as.call(c(FUN, call)) you would see something like FUN(dots[[1L]][[1L]], dots[[1L]][[2L]], dots[[1L]][[3L]]) which helps explain why you were getting the results you were getting.

How to Solve it:

You seem to want the values of your argument. You could evaluate what you get from match.call, or simpler, just use:

list(Sex, SmokingHx, conjunction)

If you want something that gets all the arguments of your function without having to know their names you can do something like:

mget(names(formals()))

Try (simplifying fun for clarity):

makeClause <-function(Sex, SmokingHx, conjunction) mget(names(formals()))

with(combinations, t(mapply(makeClause, Sex, SmokingHx, conjunction)))

Produces:

       Sex      SmokingHx conjunction
NA     "NA"     "NA"      "&"        
male   "male"   "NA"      "&"        
female "female" "NA"      "&"        
NA     "NA"     "current" "&"        
male   "male"   "current" "&"        
female "female" "current" "&"      
... further rows omitted

Upvotes: 3

Related Questions