本文是AdvancedR的functions章节的总结
文章目录
- function基础
- 函数组成(function components)
- 函数调用
- 函数调用的组织方式
- 函数参数懒求值(lazy evaluation)
- 缺省参数
- ...
- 函数返回值
- 退出函数处理函数exit handler
- 函数形式(function forms)
function基础
- function分为三部分:arguments, body, 和environment
# function的普通定义
function(arg1, arg2) { body }
# 等价于
`function`(alist(arg1, arg2), body, env)
- function是对象
函数组成(function components)
-
formals(f)
: 显示函数的参数定义。(采用args(f)
更直观) -
body(f)
: 显示函数的定义代码 -
environment(f)
: 显示该函数关联的环境
由于函数也是个对象,也有attribute,srcref属性包含所有的代码,包括注释。attr(f, "srcref")
注意: primitive function(原始函数)是R语言中采用C语言实现的核心原始函数,为了提高运行效率。primitive function类型为builtin或special。上文的显示3个组成部分的函数都返回为NULL。
函数调用
do.call(fun, args)
等于fun(args)
函数调用的组织方式
除了常用的中间变量保存结果和嵌套调用外,magrittr包提供了一种管道(pipe)调用方式%>%
:
library(magrittr)
x %>%
deviation() %>%
square() %>%
mean() %>%
sqrt()
等价于嵌套调用方式:sqrt(mean(square(deviation(x))))
函数参数懒求值(lazy evaluation)
和别的语言不同的是,函数的参数并非在调用的时候就计算好,然后传入函数;而是在函数内部执行的时候,遇到该参数,然后再根据传入的表达式进行计算。这就是所谓的lazy evaluation方式。
比如:
h01 <- function(x) {
10
}
h01(stop("This is an error!"))
#> [1] 10
由于参数x在函数内部没有用到,因此,stop("This is an error!")
永远也不会执行。
lazy evalation是由一种叫做promise的机制实现的,一个promise包含三部分:
- 一个表达式(An expression): 用于delayed compuation的表达式
- 一个环境(An environment):该表达式计算时关联的环境
- 一个值(A value):该表达式在关联环境中计算所得到的值,而且只计算一次,避免后续对该参数的引用会导致重复计算。
缺省参数
形式定义: func(x = express1, y = express2)
注意:express1, express2在参数缺失时也是lazy evaluation,不过需要注意的是,其关联的environment是该函数内部的environment。这和传入参数的environment是函数外的environment是不一样的。
函数内部可以使用missing()函数判断一个参数是否显式传入参数,返回TRUE或者FALSE。
…
变参(variable arguments)
使用…N的格式指明是第几个参数,比如:…1, …2 (比较罕见)
函数返回值
- 隐式返回:最后一个表达式的值
- 显式返回:使用return()函数
若在返回值放在invisible()函数中,则函数返回不可见,必须显示调用print或放在()中才能在命令行中显示出来。许多原始函数返回值都是不可见的,比如赋值函数:
<-
退出函数处理函数exit handler
on.exit()
在函数内部可以使用on.exit(),注册一些函数完成清理或其他工作。
函数形式(function forms)
- prefix: 前缀式
普通的函数定义: func(a, b, c) - infix: 中缀式
运算符和自定义运算符。
- x + y: `+`(x, y)
- x %op% y: `%op%`(x, y)
- replacement:替换
比如:属性赋值names(df) <- c("a", "b", "c")
等价于: `names<-`(df,c(“a”, “b”, “c”)) - special: 特殊形式的函数,包括下标符号,控制语句等
[[, if, for
如本文最开始所见,其实所有的形式,最后都翻译成统一的infix模式,包括function的普通定义:
function(arg1, arg2) {body}
# 等价于
`function`(alist(arg1, arg2), body, env)