Search code examples
rcurryingroxygen2roxygen

R Curry weirdness


I'm seeing strange behavior with the Curry function from library(roxygen). Here's a minimal example:

library(roxygen)
library(foreach)

f <- function(x,y,z) { return(x+y+z) }

fns <- list()
foreach(i=c(1:10))  %do% {
  f[[i]] <- Curry(Curry(f,i),i)
}

In this case the call

f[[1]](0) 

returns 11. I expect 2.

There are 2 fixes that don't make any sense to me - one is to flatten the loop, as in

fns <- list()
fns[[1]] <- Curry(Curry(f,1),1)
fns[[2]] <- Curry(Curry(f,2),2)
...

That works. In addition, putting a single function evaluation in the original loops works - as in

fns <- list()
foreach(i=c(1:10)) %do% {
  f[[i]] <- Curry(Curry(f,i),i)
  f[[i]](27)
}

We then have

f[[1]](0) = 2.

What's going on?


Solution

  • Restating the problem without the dependencies

    I assume Curry is defined as

    Curry<-function(FUN,...) {
      dots<-list(...);
      function(...) do.call(FUN,c(dots,list(...)))}
    

    Then

    f <- function(x,y,z) list(x,y,z)
    fns<-vector("list",10)
    for(i in 1:10) {fns[[i]]<-Curry(Curry(c,i),i)}
    fns[[1]](0)
    

    Yields

    [1] 10  1  0
    

    showing that the first argument to f was not evaluated until after the completion of the loop.

    Analysis

    This is due to lazy evaluation.

    The culprit here is a bit more subtle than Explain a lazy evaluation quirk, which is why I waffled on marking as a duplicate.

    What's being delayed here is the evaluation of FUN

    CurryF<-function(FUN,...) {
      force(FUN); #needed for nesting Curry
      dots<-list(...);
      function(...) do.call(FUN,c(dots,list(...)))}
    

    Now try again

    for(i in 1:10) {fns[[i]]<-CurryF(CurryF(c,i),i)}
    fns[[1]](0)
    

    for the expected result

    [1] 1 1 0