I am confused by the use of the ellipsis (...
) in some functions, i.e. how to pass an object containing the arguments as a single argument.
In Python it is called "unpacking argument lists", e.g.
>>> range(3, 6) # normal call with separate arguments
[3, 4, 5]
>>> args = [3, 6]
>>> range(*args) # call with arguments unpacked from a list
[3, 4, 5]
In R for instance you have the function file.path(...)
that uses an ellipsis. I would like to have this behaviour:
> args <- c('baz', 'foob')
> file.path('/foo/bar/', args)
[1] 'foo/bar/baz/foob'
Instead, I get
[1] 'foo/bar/baz' 'foo/bar/foob'
where the elements of args
are not "unpacked" and evaluated at the same time. Is there a R equivalent to Pythons *arg
?
The syntax is not as beautiful, but this does the trick:
do.call(file.path,as.list(c("/foo/bar",args)))
do.call
takes two arguments: a function and a list of arguments to call that function with.
You can extract information from the ellipsis by calling list(...)
inside the function. In this case, the info in the ellipsis is packaged as a list object. For example:
> foo <- function(x,...){
+ print(list(...))
+ }
> foo(1:10,bar = 'bar','foobar')
$bar
[1] "bar"
[[2]]
[1] "foobar"
You can achieve the desired behaviour from vectorised functions like file.path
with a call to do.call
, which is sometimes simpler to use with the wrapper splat
(in the plyr
package)
> args <- c('baz', 'foob')
> library(plyr)
> splat(file.path)(c('/foo/bar', args))
[1] "/foo/bar/baz/foob"
It took me a while to find it, but the purrr
package has an equivalent to plyr::splat
: it's called lift_dl
.
The "dl" in the name stands for "dots to list", as it's part of a series of lift_xy
functions that can be used to "lift" the domain of a function from one kind of input to another kind, these "kinds" being lists, vectors and "dots".
Since lift_dl
is probably the most useful of those, there is a simple lift
alias provided for it.
To reuse the above example:
> library(purrr)
> args <- c('baz', 'foob')
> lift(file.path)(c('/foo/bar', args))
[1] "/foo/bar/baz/foob"