闭包的执行顺序

时间:2017-06-10 02:46:21

标签: r closures lapply

这是我创建的一个测试函数,用于了解lapply和闭包的交互方式。我的目标是按顺序迭代runif函数并打印每次迭代。

Mod_delay_by <- function(delay,f){
  function(x,...){
    Sys.sleep(delay)
    cat(".")
    #f(x,...)
    cat("Processing",x,"\n",sep = "")
    f(x,...)
    }
}

现在让我们使用lapply来调用上面的函数:

lapply(1:3,Mod_delay_by(0.1,runif))

当我调用上面的函数时,我得到以下示例输出:

.Processing1
.Processing2
.Processing3
[[1]]
[1] 0.835246

[[2]]
[1] 0.1370997 0.4350032

[[3]]
[1] 0.1174749 0.4087628 0.7222604

我很惊讶,因为所有三个“.Processing”都在执行runif之前到来。相反,我本来期望输出是......

.Processing1
[[1]]
[1] 0.835246

.Processing2
[[2]]
[1] 0.1370997 0.4350032

.Processing3
[[3]]
[1] 0.1174749 0.4087628 0.7222604

...因为runif(即函数f)之后会立即调用“.Processing”

有人可以解释为什么lapply首先完成所有三个Processing的打印,然后打印所有三个runifs

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

默认情况下,函数不会向控制台打印任何内容。

.Processing1
.Processing2
.Processing3
[[1]]
[1] 0.835246

[[2]]
[1] 0.1370997 0.4350032

[[3]]
[1] 0.1174749 0.4087628 0.7222604

你来了

.Processing1
.Processing2
.Processing3

因为您使用的是cat而其余的来自lapply输出。

如果您更改此定义的功能

Mod_delay_by <- function(delay,f){
  function(x,...){
    Sys.sleep(delay)
    cat(".")
    #f(x,...)
    cat("Processing",x,"\n",sep = "")
    print(f(x,...))
    }
}

然后运行

lapply(1:3,Mod_delay_by(0.1,runif))

你会得到

#.Processing1
#[1] 0.5281055
#.Processing2
#[1] 0.892419 0.551435
#.Processing3
#[1] 0.4566147 0.9568333 0.4533342
#[[1]]
#[1] 0.5281055
#
#[[2]]
#[1] 0.892419 0.551435
#
#[[3]]
#[1] 0.4566147 0.9568333 0.4533342

答案 1 :(得分:1)

显然,OP期望f()的输出应该打印到每个调用中的控制台窗口cat()

与直接从控制台窗口调用函数时发生的情况类似:

> Mod_delay_by(0.1, runif)(2)
.Processing2
[1] 0.4519318 0.2331198

请注意,如果输出分配给变量,我们将不会看到任何打印的内容(cat()的输出除外):

> result <- Mod_delay_by(0.1, runif)(2)
.Processing2

因此,如果您从控制台窗口调用一个函数并且输出而不是分配给变量,则会将其打印到控制台窗口。

现在,f()正在从函数体中调用。这种情况不同。

f()的输出不会打印到控制台窗口,而是返回给调用者。帮助文件?"function"表示如果在未调用return的情况下到达函数结尾,则返回上次计算的表达式的值。

通过编写

可以更明确地做到这一点
return(f(x, ...))

因此,只有cat()打印到控制台。 f()的输出返回到调用lapply()函数,该函数收集列表中的所有输出。最后,此列表仅打印到控制台,因为它未分配给变量

如果将输出分配给变量,除了cat()打印到控制台之外,我们不会看到任何打印内容。

> result <- lapply(1:3, Mod_delay_by(0.1, runif))
.Processing1
.Processing2
.Processing3

总而言之,R正在尝试保存输入,但结果取决于上下文:

  • 在控制台窗口中,f()没有分配意味着print(f())

  • 在函数体中,f()作为上次评估的表达式隐含return(f())