为什么 `lapply` returns 自动分配结果?
Why `lapply` returns result of assignment automatically?
q <- lapply(1:3, function(x) x ** 2)
## returns nothing, because it is an assignment
# however, how you explain this?:
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
# while this gives the same but is logical (q is stated as return value).
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) {q <- lapply(v, function(x) x ** 2);q})
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
为什么在第二个表达式中,虽然里面的lapply
只是赋值给了q
,但是q
并没有在函数结束时被调用,赋值的值
返回到外部lapply
并因此被收集?
请问有人对这种现象有解释吗?
它也适用于 =
lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q = lapply(c(v), function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
答案在于赋值操作的return值。赋值运算符 <-
不仅将值写入调用环境中的变量,它实际上还无形地 return 将赋值本身发送给调用者。
记住 R 中的所有操作实际上都是函数。当你这样做时
x <- 3
你其实在做
`<-`(x, 3)
这不仅在调用环境中创建符号“x”并将值 3 分配给该符号,而且无形地return将值 3 分配给调用者.要看到这一点,请考虑:
y <- 2
y
#> [1] 2
y <- `<-`(x, 3)
y
#> [1] 3
或等价地,
y <- (x <- 4)
y
#> [1] 4
事实上,由于 R 的求值顺序,我们甚至可以这样做:
y <- x <- 5
y
#> [1] 5
这是在同一行中将多个变量设置为相同值的巧妙方法。
现在考虑在 lapply
:
中使用的 lambda 函数
function(v) q <- lapply(v, function(x) x ** 2)
看看当我们将此功能视为独立功能时会发生什么:
func <- function(v) q <- lapply(v, function(x) x ** 2)
func(1:3)
正如预测的那样,没有任何反应。但是当我们这样做时会发生什么:
a <- func(1:3)
如果 func(1:3) 没有 return 任何东西,那么大概 a
现在应该是空的。
但这不是...
a
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 4
#>
#> [[3]]
#> [1] 9
因为赋值的值被 return 无形地传递给了调用者,我们能够将它赋值给调用范围内的值。因此,做
lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
将应用于所有列表元素的内部函数的值分配给新列表。此列表 不是 return 不可见的,而是 return 正常编辑的。
所以这是预期的行为。
q <- lapply(1:3, function(x) x ** 2)
## returns nothing, because it is an assignment
# however, how you explain this?:
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
# while this gives the same but is logical (q is stated as return value).
> lapply(list(1:3, 4:6, 7:9, 10:11), function(v) {q <- lapply(v, function(x) x ** 2);q})
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
为什么在第二个表达式中,虽然里面的lapply
只是赋值给了q
,但是q
并没有在函数结束时被调用,赋值的值
返回到外部lapply
并因此被收集?
请问有人对这种现象有解释吗?
它也适用于 =
lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q = lapply(c(v), function(x) x ** 2))
[[1]]
[[1]][[1]]
[1] 1
[[1]][[2]]
[1] 4
[[1]][[3]]
[1] 9
[[2]]
[[2]][[1]]
[1] 16
[[2]][[2]]
[1] 25
[[2]][[3]]
[1] 36
[[3]]
[[3]][[1]]
[1] 49
[[3]][[2]]
[1] 64
[[3]][[3]]
[1] 81
[[4]]
[[4]][[1]]
[1] 100
[[4]][[2]]
[1] 121
答案在于赋值操作的return值。赋值运算符 <-
不仅将值写入调用环境中的变量,它实际上还无形地 return 将赋值本身发送给调用者。
记住 R 中的所有操作实际上都是函数。当你这样做时
x <- 3
你其实在做
`<-`(x, 3)
这不仅在调用环境中创建符号“x”并将值 3 分配给该符号,而且无形地return将值 3 分配给调用者.要看到这一点,请考虑:
y <- 2
y
#> [1] 2
y <- `<-`(x, 3)
y
#> [1] 3
或等价地,
y <- (x <- 4)
y
#> [1] 4
事实上,由于 R 的求值顺序,我们甚至可以这样做:
y <- x <- 5
y
#> [1] 5
这是在同一行中将多个变量设置为相同值的巧妙方法。
现在考虑在 lapply
:
function(v) q <- lapply(v, function(x) x ** 2)
看看当我们将此功能视为独立功能时会发生什么:
func <- function(v) q <- lapply(v, function(x) x ** 2)
func(1:3)
正如预测的那样,没有任何反应。但是当我们这样做时会发生什么:
a <- func(1:3)
如果 func(1:3) 没有 return 任何东西,那么大概 a
现在应该是空的。
但这不是...
a
#> [[1]]
#> [1] 1
#>
#> [[2]]
#> [1] 4
#>
#> [[3]]
#> [1] 9
因为赋值的值被 return 无形地传递给了调用者,我们能够将它赋值给调用范围内的值。因此,做
lapply(list(1:3, 4:6, 7:9, 10:11), function(v) q <- lapply(v, function(x) x ** 2))
将应用于所有列表元素的内部函数的值分配给新列表。此列表 不是 return 不可见的,而是 return 正常编辑的。
所以这是预期的行为。