|
这一部分的内容相对本文档其他部分的内容更偏向一些技术性的问题。但是它会
澄清SPLUS 和R 一些重要的差异。
函数内部的变量可以分为三类:形式参数(formal parameters),局部变量(local
variables)和自由变量(free variables)。形式参数是出现在函数的参数列表中的变量。
它们的值由实际的函数参数绑定形式参数的过程决定的。局部变量由函数内部表达式
的值决定的。既不是形式参数又不是局部变量的变量是自由变量。自由变量如果被赋
值将会变成局部变量。观察下面的函数定义过程,
f <- function(x) {
y <- 2*x
print(x)
print(y)
print(z)
}
在这个函数中,x 是形式参数,y 是局部变量,z 是自由变量。
在R 里面,可以利用函数被创建的环境中某个变量的第一次出现解析一个自由变
量的绑定。这称为词法作用域(lexical scope)。我们可以定义一个函数cube,
cube <- function(n) {
sq <- function() n*n
n*sq()
}
函数sq 中的变量n 不是函数的参数。因此它是自由变量。一些作用域的原则可以
用来确定和它相关的值。在静态作用域(SPLUS)中,这个值指的是一个和全局变量n
相关的值。在词法作用域(R)中,它指的是函数cube 的参数。因为当sq 定义的时候,
它会动态绑定参数n。在R 里面解析和在SPLUS 里面解析不同点在于SPLUS 搜索全
局变量n 而R 首先寻找函数cube调用时所创建的环境中的变量n。
## 首先用\sm{S} 解析
S> cube(2)
Error in sq(): Object "n" not found
Dumped
S> n <- 3
S> cube(2)
[1] 18
## 同样的函数在\R{} 中解析}
R> cube(2)
[1] 8
词汇作用域会给予函数可变状态(mutable state)。下面的例子演示R 如何模仿
一个银行的帐户。真正的银行帐户必须同时有跟踪收支平衡或者总额的变量,提供提
款业务,取款业务和显示当前余额的函数。我们可以在account 里面创建三个函数,
然后返回一个包含它们的的列表。当调用account 时,它读入一个数值参数total,
并且返回一个包含三个函数的列表。因为这些函数时定义在一个有变量total 的环境
中,它们可以访问它的值。
<<- 是一个特别的赋值操作符,它用来更改和total 相关的值。这个操作符会回
溯到一个含有标识符total 的密闭环境中。当它找到这个环境,它会用操作符右边的
值替换环境中这个变量的值。如果在全局变量或者最高层次的环境中仍然没有找到标
识符total,那么该变量就会被创建并且在那里被赋值。大多数用户用<<- 创建全局
变量,并且把操作符右边的值赋给它4。仅仅当<<- 用于一个函数的输出是另外一个函
数的输入时,这里描述的独特行为才会出现。
open.account <- function(total) {
list(
deposit = function(amount) {
if(amount <= 0)
stop("Deposits must be positive!\n")
total <<- total + amount
cat(amount, "deposited. Your balance is", total, "\n\n")
},
withdraw = function(amount) {
if(amount > total)
stop("You don't have that much money!\n")
total <<- total - amount
cat(amount, "withdrawn. Your balance is", total, "\n\n")
},
balance = function() {
cat("Your balance is", total, "\n\n")
}
)
}
ross <- open.account(100)
robert <- open.account(200)
ross$withdraw(30)
ross$balance()
robert$balance()
ross$deposit(50)
ross$balance()
ross$withdraw(500)
|
|