• R语言
  • Advanced R programming手记

"In fact, the fundamental design principle underlying R (and S) is “everything

is an object”. Hence, not only vectors and matrices are objects that

can be passed to and returned by functions, but also functions themselves,

and even function calls."

回复 第9楼 的 zggjtsgzczh:Springer的Use R!系列的《Applied Econometrics with R》

回复 第4楼 的 superdesolator:我也是工作需要最近一年才正式用R, 没事的时候看看大牛的个人主页 最近迷上了谢老大的knitr

自己也正在学习,共同学习![s:13]

回复 第1楼 的 yiluheihei:

求教一下:

关于其中的lazy evaluation中前一个例子还好理解,但是后面的关于adder的例子则

不好懂了。

<br />
add1 <- add(1)<br />
add2 <- add(2)</p>
<p>add1(10)<br />
# 结果为11</p>
<p>add2(10)<br />
# 结果为12<br />


上面的例子和作者的例子区别在哪呢?</p>

我感觉在用lapply()时,同样也把1:10一个个传给add(),然后x依次等于1:10,并且

利用x才能生成adders列表的一个个元素。这里x用到了啊?求解释!

回复 第13楼 的 lovecos:以前看的时候也有同样的疑惑. 现在感觉这个和lapply的行为非常相关.

在返回adders函数系列的时候,x 的确没有使用,只有当这些函数被调用的时候,x 才会求值,这正是Lazy evaluation的行为.

拿add1函数为例,当调用add1(10)被执行时,x开始求值.但add1函数定义内并没有x的定义,只能向上层环境中查找(词法作用域).上层环境是add()函数的执行环境(每执行一次,这个环境都不相同),这里x是一个实参,它的值是在add()的被调用环境中查找的(非默认实参的求值环境),这个"被调用环境"就是lapply里面.在lapply执行完成时,x的值是10,所以add1(10) => 20. 

整个过程里最难理解的就是lapply是怎么把1:10的每个元素传递给add函数的.不过可以肯定的是:它传递的肯定不是1, 2, 3... 这些值.如楼主所说,参数被求值之前是一个promise对象,所以这和promise对象的行为应该也有关系.但lapply最终调用一个.Internal(lapply),要想知道它的运行机制,可能需要去看R的源代码了.

回复 第13楼 的 lovecos:我的理解跟14楼差不多, 当lapply作用于函数add时

<br />
# 没有用到x且函数的返回值是一个function, 就没在环境中寻找x的值, 会返回function(y)x+y<br />
 function(y)x+y<br />
`

lapply之后在add()函数的函数的环境中x是10,
<br />
adders[[1]] <- function(y)x+y<br />
# 返回一个数值, 依次从adders函数到父环境中寻值x=10<br />
adders[[1]](10)<br />
## 20<br />


不晓得对不对

`
</p>

谢谢manxingxing和楼主的回答,可能我忽略了一个定义:

“用到”和“计算(evaluate)”是两码事,在执行

<br />
adders <- lapply(1:10, add)<br />


仅仅是“用”add()函数中的参数x来表示adders列表的每一个元素(或组分),

但是一直没有对x进行计算(即x没有被evaluated)。

等到执行执行
<br />
adders[[1]](10)<br />


这时,就需要计算add()函数中的x值了,而经过lapply的循环后,最后传递给

add()的参数已经是10了,即x为10,所以就得到了上述的结果。</p>

望批评指正[s:13]

研究了一会,我也比较同意14楼说的,即最后调用的时候,查找x的方法,不管是adders[[1]]还是adders[[2]],它们本身的function里没有x,必须去它们的"外面"找x,而问题就是这个"外面"是在哪里,这就需要对lapply这个函数和promise这个东西弄清楚了...

另外,我实验了一下,觉得lazy的特性一个方面如下:

<br />
add=function(x=a()) #我a()并没定义<br />
{<br />
return(1)<br />
}<br />
add()<br />


这lazy到甚至不会去管a()其实是不存在的,直接返回1,所以LZ提到"没用到x",就会lazy,这个判断用不用到,可能是x没有被evalued吧?

另外的另外,对于默认实参从函数内部找,这句话,应该改为首先从函数内部查找,如果内部没有,则到外部找
<br />
f=function(x=h){<br />
h=1<br />
x<br />
}<br />
f()<br />
h=2<br />
f2=function(x=h){<br />
x}<br />
f2()<br />
h=3<br />
f3=function(x=h)<br />
{<br />
h=4<br />
x<br />
}<br />
f3()<br />
</p>
6 个月 后