image.png
函数是 R 语言中的基本构建块 ,所有的操作都是函数调用, 比如+, 控制流运算符,比如for、 if 和 while, 取子集操作符,比如[]和$,甚至花括号{

函数的组成

  1. func <- function(x){
  2. x <- x + 1
  3. }

r语言的函数由三部分组成

  • 函数体, body(),函数的代码。
  • 参数, formals(),控制函数调用的参数列表。
  • 环境, environment(),函数的变量所在位置的”地图”

函数还可以拥有任意数量的附加属性

原语函数

原语函数(Primitive functions),sum(),它直接使用了.Primitive()调用 C 语言代码,并且不包含 R 语言代码。 因此,它们的 formals()、 body()和 environment()都是 NULL ,原语函数仅仅存在于base包中

词法作用域

作用域是一组规则,这些规则控制着 R 语言如何查找符号的值
R 语言有两种类型的作用域:

  • 词法作用域(Lexical scoping),在语言层面自动实现,跟函数创建密切相关
  • 动态作用域(Dynamic scoping),用于在交互式分析情景下,在选择函数时,可以减少键盘输入。

词法作用域进行符号的值的查找,是基于在函数创建时是如何嵌套的,而不是它们在调用时如何嵌套的。 有四个基本原则

  1. 名字屏蔽
  2. 函数和变量
  3. 全新的开始状态
  4. 动态查找

    名字屏蔽(name masking)

    名字在函数中没有定义,那么 R 语言将向上一个层次查找。 首先,查看当前函数的内部,然后是这个函数被定义的环境,然后继续向上,以此类推,一直到全局环境,然后,再查找其它已经加载的包。 ```r f <- function() { x <- 1 y <- 2 c(x, y) }

f() [1] 1 2


f <- function(x){ y <- 1 function(){ c(x, y) } }

a <- f(100) a() [1] 100 1

a function(){ print(c(x, y)) }

ls(environment(a)) [1] “x” “y” ls(environment(f)) [1] “a” “f” “f2” “y”

  1. <a name="ySebs"></a>
  2. ### 函数和变量
  3. 无论关联了什么类型的值,都适用同样的原则——搜索函数与搜索变量的过程完全一样,对于函数,规则有一点点调整。 如果很明显你要的是函数(例如,f(3)),那么在这样的语境中, R 语言在搜索时,将忽略那些不是函数的对象。
  4. <a name="eNAzV"></a>
  5. ### 全新的开始状态
  6. 每一次函数被调用时,一个新的环境就会被创建出来,随后,函数会在该环境中执行。 函数无法报告它上一次调用时发生了什么,因为每次调用都是完全独立的
  7. <a name="Udts2"></a>
  8. ### 动态查找
  9. 词法作用域决定了去哪里查找值,而不是决定在什么时候查找值。 R 语言在函数运行时查找值,而不是在函数创建时查找值。 这意味着,**函数的输出是可以随着它所处的环境外面的对象,而发生变化的 **<br />**通常应该避免这种行为,因为这意味着函数不再是独立的。 这是一种常见的错误**<br />**可以使用**codetools::findGlobals()查找外部依赖
  10. ```r
  11. f <- function(){
  12. x
  13. }
  14. x <- 8
  15. > codetools::findGlobals(f)
  16. [1] "{" "x"

函数参数

函数调用

当调用一个函数时,你可以通过参数的位置,或者通过完整的名称或者部分的名称,来匹配参数。 参数匹配的顺序是:首先是精确的名称匹配(完美匹配),然后通过前缀匹配,最后通过位置匹配。...之后列出的参数都必须使用它们的全名, 前缀匹配能不用就不用

参数列表

使用do.call()函数可以将一个参数列表传给相应的函数

  1. do.call(mean, list(1:10, na.rm = TRUE))
  2. #> [1] 5.5
  3. # 相当于
  4. mean(1:10, na.rm = TRUE)

默认参数和延迟计算

R 语言中的函数参数可以有默认值由于在 R 语言中参数都是延迟计算的,所以参数的默认值可以使用其它参数定义

中缀函数

R中大多数函数是前缀操作符, 即函数名称排在函数前,中缀函数,即函数名称位于参数之间,如 +%in%,R中内置的中缀函数如下,

  1. %%、 %*%、 %/%、 %in%、 %o%、 %x%
  2. ::, :::, $, @, ?, *, /, +, -, >, >=, <, <=, ==, !=, !, &, &&, |, ||, ~, <-, <<-

创建一个中缀函数(R 的默认优先规则意味着中缀操作符是从左到右进行结合的 )

  1. `%+%` <- function(a, b) paste(a, b, sep = "")
  2. "new" %+% " string"
  3. #> [1] "new string

替换函数

替换函数的行为表现为就地修改,函数名称为xxx<-

  1. `second<-` <- function(x, value) {
  2. x[2] <- value
  3. x }
  4. x <- 1:10
  5. second(x) <- 5L
  6. x
  7. #> [1] 1 5 3 4 5 6 7 8 9 10
  8. # 创建一个随机修改向量元素值的替换函数
  9. `change<-` <- function(x, value){
  10. x[sample(1:length(x), 1)] <- value
  11. x
  12. }
  13. x <- c(1:12)
  14. change(x) <- sample(1:1000, 1)
  15. ## 三次运行结果
  16. [1] 444 2 3 4 5 6 7 8 9 10 11 12
  17. [1] 444 486 3 4 5 6 7 8 9 10 11 12
  18. [1] 444 486 3 4 5 6 7 8 9 10 11 930

返回值

函数中最后一个表达式的计算结果会成为函数的返回值,也就是调用函数的结果,纯函数(pure function):这种函数总是把相同的输入映射到相同的输出,并且不影响工作空间。 换句话说, 纯函数没有副作用:除了返回值外,它们不以任何方式影响其它状态