问题
I have a question on the scope of dot-dot-dot arguments. Consider the following function`foo =
foo <- function(x, ...){
require(classInt);
intvl = classIntervals(x, ...);
return(intvl);
}
The function works great for the following calls
x = runif(100, 0, 100);
y1 = foo(x, n = 5, style = 'quantile');
y2 = foo(x, style = 'equal');
But when I try to use the style = 'fixed' argument, which needs a fixedBreaks argument as well, I get
y3 = foo(x, style = 'fixed', fixedBreaks = seq(0, 100, 20))
Error in eval(expr, envir, enclos) : The ... list does not contain 2 elements
Note that the following works perfectly
y5 = classIntervals(x, style = 'fixed', fixedBreaks = seq(0, 100, 20))
I suspsect that this has something to do with scoping rules, but have been unable to put my finger on it. Any help on this would be very much appreciated.
EDIT. I cobbled up a simpler hack that makes it work. I think it is a match.call issue, as the same problem exists for style = 'pretty'. A quick look at the code shows that these are the two styles for which such match.calls are made, so quite likely this is the source of error. Any case, here is my proposed hack
foo2 <- function(x, ...){
require(classInt);
y = list(...); y$var = x;
intvl = do.call('classIntervals', y);
}
y6 = foo2(x, style = 'fixed', fixedBreaks = seq(0, 100, 20))
I think Richie's answer to my question sheds some light on why my earlier code failed to work. But, I still don't understand why this one does.
回答1:
Inside the foo
function, the ellipsis does contain 2 elements. Call this modification to see this.
foo <- function(x, ...){
require(classInt);
print(list(...))
intvl = classIntervals(x, ...);
return(intvl);
}
Once classIntervals
is called, the ellipsis changes, since arguments are matched differently. Here's the signature for that function
classIntervals(var, n, style = "quantile", rtimes = 3, ...,
intervalClosure = "left", dataPrecision = NULL)
In your call that fails, you have three arguments
foo(x, style = 'fixed', fixedBreaks = seq(0, 100, 20))
x
gets matched up to var
through positional matching (i.e., because it's in the first position in the signature in each case).
style
gets matched up to style
, via name matching (because they have the same name, duh).
fixedBreaks
can't be matched by position or name so it ends up in the dots.
Thus the ellipsis contains 1 argument, and the error "The ... list does not contain 2 elements" is correct (if rather silly).
EDIT: Suggested fix to classIntervals
. If you are contacting the author, then suggest replacing lines 42-43
mc <- match.call(expand.dots = FALSE)
fixedBreaks <- sort(eval(mc$...$fixedBreaks))
with
fixedBreaks <- list(...)$fixedBreaks
This is (I think) what they meant, and seemes to solve the silly error message.
来源:https://stackoverflow.com/questions/5207672/scope-of-dot-dot-dot-arguments