Using "..." and "replicate"
Asked Answered
D

4

19

In the documentation of sapply and replicate there is a warning regarding using ...

Now, I can accept it as such, but would like to understand what is behind it. So I've created this little contrived example:

innerfunction<-function(x, extrapar1=0, extrapar2=extrapar1)
{
    cat("x:", x, ", xp1:", extrapar1, ", xp2:", extrapar2, "\n")
}

middlefunction<-function(x,...)
{
    innerfunction(x,...)
}

outerfunction<-function(x, ...)
{
    cat("Run middle function:\n")
    replicate(2, middlefunction(x,...))
    cat("Run inner function:\n")
    replicate(2, innerfunction(x,...))
}

outerfunction(1,2,3)
outerfunction(1,extrapar1=2,3)
outerfunction(1,extrapar1=2,extrapar2=3)

Perhaps I've done something obvious horribly wrong, but I find the result of this rather upsetting. So can anyone explain to me why, in all of the above calls to outerfunction, I get this output:

Run middle function:
x: 1 , xp1: 0 , xp2: 0 
x: 1 , xp1: 0 , xp2: 0 
Run inner function:
x: 1 , xp1: 0 , xp2: 0 
x: 1 , xp1: 0 , xp2: 0

Like I said: the docs seem to warn for this, but I do not see why this is so.

Donitadonjon answered 15/7, 2011 at 8:40 Comment(0)
W
12

?replicate, in the Examples section, tells us explicitly that what you are trying to do does not and will not work. In the Note section of ?replicate we have:

     If ‘expr’ is a function call, be aware of assumptions about where
     it is evaluated, and in particular what ‘...’ might refer to.  You
     can pass additional named arguments to a function call as
     additional named arguments to ‘replicate’: see ‘Examples’.

And if we look at Examples, we see:

 ## use of replicate() with parameters:
 foo <- function(x=1, y=2) c(x,y)
 # does not work: bar <- function(n, ...) replicate(n, foo(...))
 bar <- function(n, x) replicate(n, foo(x=x))
 bar(5, x=3)

My reading of the docs is that they do far more than warn you about using ... in replicate() calls; they explicitly document that it does not work. Much of the discussion in that help file relates to the ... argument of the other functions, not necessarily to replicate().

Westfalen answered 15/7, 2011 at 9:25 Comment(5)
Note that in the example, event the "correct" way doesn't work properly - it is replicated x times (3) rather than n times (5).Joby
@Joby - not on my system. I get a 2*5 matrix for bar(5, x = 3)Westfalen
Oops, my mistake. Had a typo when transcribing the examples.Joby
@Gavin: The quote from ?replicate is the warning I mentioned in my question. What I would like to know is what this warning means? 'where it is evaluated' and 'what ... might refer to' are somewhat cryptic to me. So, again: I accept that it doesn't work, but why doesn't it work? This might greatly help my/others' understanding of argument passing/parsing in R.Donitadonjon
@Nick sorry for late reply; To my mind, the reason this doesn't work is that you are not calling the function in expr, you are just evaluating expr. Because you are not calling it, there is no passing of arguments from the outer call ... to the expr. This is a subtle difference but is very important; it is as if you called middlefunction(...) exactly like that in the global environment (you can't because R doesn't allow you to use ... interactively like that) where ... doesn't refer to anything.Westfalen
J
6

If you look at the code for replicate:

> replicate
function (n, expr, simplify = TRUE) 
sapply(integer(n), eval.parent(substitute(function(...) expr)), 
    simplify = simplify)
<environment: namespace:base>

You see that the function is evaluated in the parent frame, where the ... from your calling function no longer exists.

Joby answered 15/7, 2011 at 10:26 Comment(0)
A
1

There actually is a way to do this:

# Simple function:
ff <- function(a,b) print(a+b)

# This will NOT work:
testf <- function(...) {
  replicate(expr = ff(...), n = 5)
}
testf(45,56) # argument "b" is missing, with no default

# This will:
testf <- function(...) {
  args <- as.list(substitute(list(...)))[-1L]
  replicate(expr = do.call(ff, args), n = 5)
}
testf(45,56) # 101
Agustinaah answered 27/4, 2015 at 1:5 Comment(0)
B
0

An alternative way to do that:

g <- function(x, y) x + y

f <- function(a = 1, ...) {
    arg_list <- list(...)
    replicate(n = 3, expr = do.call(g, args = arg_list))
}

f(x = 1, y = 2)
Buddhism answered 7/3, 2018 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.