How to not fall into R's 'lazy evaluation trap'

后端 未结 4 947
执念已碎
执念已碎 2021-02-04 05:40

\"R passes promises, not values. The promise is forced when it is first evaluated, not when it is passed.\", see this answer by G. Grothendieck. Also see this question referring

4条回答
  •  生来不讨喜
    2021-02-04 06:13

    You are creating functions with implicit parameters, which isn't necessarily best practice. In your example, the implicit parameter is i. Another way to rework it would be:

    library(functional)
    myprint <- function(x) print(x)
    funs <- lapply(1:10, function(i) Curry(myprint, i))
    funs[[1]]()
    # [1] 1
    funs[[2]]()
    # [1] 2
    

    Here, we explicitly specify the parameters to the function by using Curry. Note we could have curried print directly but didn't here for illustrative purposes.

    Curry creates a new version of the function with parameters pre-specified. This makes the parameter specification explicit and avoids the potential issues you are running into because Curry forces evaluations (there is a version that doesn't, but it wouldn't help here).

    Another option is to capture the entire environment of the parent function, copy it, and make it the parent env of your new function:

    funs2 <- lapply(
      1:10, function(i) {
        fun.res <- function() print(i)
        environment(fun.res) <- list2env(as.list(environment()))  # force parent env copy
        fun.res
      }
    )
    funs2[[1]]()
    # [1] 1
    funs2[[2]]()
    # [1] 2
    

    but I don't recommend this since you will be potentially copying a whole bunch of variables you may not even need. Worse, this gets a lot more complicated if you have nested layers of functions that create functions. The only benefit of this approach is that you can continue your implicit parameter specification, but again, that seems like bad practice to me.

提交回复
热议问题