3

I want to implement another version of lapply function that allows me to specify whether to run in parallel. The code is like this:

papply <- function(x,fun,...,
  parallel=FALSE,parallel.options=list(mode="socket",cpus=2),
  integrate=rbind,convert=NULL) {
  if(parallel) {
    require(parallelMap)
    do.call(parallelStart,parallel.options)
    result <- parallelLapply(x,fun,...)
    parallelStop()
  } else {
    result <- lapply(x,fun,...)
  }
  if(is.function(integrate)) {
    result <- do.call(integrate,result)
  }
  if(is.function(convert)) {
    result <- convert(result)
  }
  return(result)
}

If parallel=TRUE, I use parallelLapply() in {parallelMap} package, otherwise I use ordinary lapply function. In both methods, the vector/list I try to map is x and the mapping function is fun. Since fun may have more than one parameters, I use ... to pass additional arguments to fun.

However, if no additional arguments are specified, like

papply(1:5,function(i,x){return(data.frame(a=i,b=i+1))})

It works fine and returns correct values:

  a b
1 1 2
2 2 3
3 3 4
4 4 5
5 5 6

But if additional arguments are specified, like

papply(1:5,function(i,x){return(data.frame(a=i,b=i+x))},x=1)

It does not work out but reports an error like

 Error in get(as.character(FUN), mode = "function", envir = envir) : 
  object 'fun' of mode 'function' was not found 
4 get(as.character(FUN), mode = "function", envir = envir) 
3 match.fun(FUN) 
2 lapply(x, fun, ... = ...) at utils.R#37
1 papply(1:5, function(i, x) {
    return(data.frame(a = i, b = i + x))
}, x = 1) 

I don't know why this error occurs. How can I resolve the error and make the function work?

Kun Ren
  • 4,715
  • 3
  • 35
  • 50

1 Answers1

4

This comes down to a positional matching and argument naming issue.

x is formal argument of papply, therefore, when you name it in

papply(1:5, function(i, x) {return(data.frame(a=i, b=i+x))}, x=1)

This means that 1:5 is matched as fun --> hence the error.

In the current form of your function it is impossible for R to know that when you denote x=1 that you want this to be considered in the ... component.

See the MoreArgs argument to mapply as an approach that might be useful.

ah bon
  • 9,293
  • 12
  • 65
  • 148
mnel
  • 113,303
  • 27
  • 265
  • 254
  • The error indeed indicates that `1:5` is matches as `fun`, but why this could happen? – Kun Ren Feb 19 '14 at 13:33
  • @KunRen - `papply` has two named arguments `x` and `fun`. you have named `x` in your call to `papply`. Positional matching then matches the first unnamed argument with the first formal argument yet to have a value. Therefore `1:5` is matched as `fun`. Change the function definition so that you don't have the same argument names in both functions and you should be fine. – mnel Feb 19 '14 at 22:18
  • @mnei - Yes, it really works after I change `x` to `.x` and `fun` to `.fun`. It's so tricky to name the arguments when `...` appears. Thanks! – Kun Ren Feb 20 '14 at 00:12