3

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

AdrienF
  • 859
  • 1
  • 6
  • 19
  • Please make your sample [reproducible](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example). Include a minimal dataset we can test with. Show how you are actually calling `mapply()`. – MrFlick Feb 26 '15 at 22:16
  • Edited, sorry about that – AdrienF Feb 26 '15 at 22:22
  • I cannot reproduce your error with "$conjunction" with this example. The fact that is has a "[4L]" there makes me think there is somewhere that "conjunction" is spelled wrong or there's an extra comma somewhere. – MrFlick Feb 26 '15 at 22:30
  • Does your function really need named parameters? If not and you just want to do something for all of them, how about just `makeClause <-function(...) {arglist = list(...)}` – MrFlick Feb 26 '15 at 22:33
  • @MrFlick, but you lose the argument matching and potential re-ordering from doing that. – BrodieG Feb 26 '15 at 22:35
  • @BrodieG Good points. I think your suggestion of using `list(Sex, SmokingHx, conjunction)` with the named parameters makes most sense. If you went through the trouble of naming them, then use those names in the function rather than treating parameters as an arbitrary list of values. – MrFlick Feb 26 '15 at 22:41
  • @MrFlick good point, I guess I just wanted to see how you could get arguments within the function in general, even if they weren't named – AdrienF Feb 26 '15 at 22:43

1 Answers1

3

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
BrodieG
  • 51,669
  • 9
  • 93
  • 146