R语言元编程metaprogramming基础函数

R语言元编程基础函数

所谓的元编程(metaprogramming)其实就是编写运行时动态修改程序本身的代码(编写产生代码的代码)。 R语言支持元编程,有几个基础函数需要深入了解:

substitute

替换函数。形式substitute(expr, env),表达式expr中的变量使用env中的绑定的变量的值(若是函数参数,因为是promise的缘故还没有eval)替换,env不进行回溯,只在当前或指定的env中搜索。而且env不能是.GlobalEnv,如果是.GlobalEnv,不进行替换。env可以是list。

A promise捕获(capture)了需要计算的表达式(但是没有计算eval),以及计算表达式所处的environment. 第一次访问promise时,触发表达式的计算,从而产生environment中的表达式对应绑定对象的值。promise就像“薛定谔的猫”,一旦访问,就触发计算,从而退出promise状态。

a <- 1
b <- 11
res1 <- substitute(x + y, list(x = sin(3), y = a/b)) 
# 0.141120008059867 + 0.0909090909090909

c(class(res1), typeof(res1))  
# [1] "call"     "language"

sf <- function(x, y) {
  substitute(x + y)  
}

res2 <- sf(sin(10), a/b)     
# sin(10) + a/b

c(class(res2), typeof(res2)) 
# [1] "call"     "language"

substitute不仅变量能够替换,运算符(函数)也能够替换:

> substitute(a + b, list("+" = quote(func)))
func(a, b)

quote

quote(expr)
简单地返回expr,expr没有进行eval。和substitute相比,没有替换。

res3 <- quote(a/b)
# a/b

c(class(res3), typeof(res3))
# [1] "call"     "language"

subtitute/quote返回class/type根据表达式的不同而不同。表达式被解析为抽象语法树,可以访问其中每一个组成,还可以对返回的对象进行修改,即自己构造语法树(meta-programming)。

eval

eval(expr, envir = parent.frame(),
           enclos = if(is.list(envir) || is.pairlist(envir))
                       parent.frame() else baseenv())

对expr进行计算,默认是当前环境(也就是eval的parent.frame)。如果envir是list/data.frame,encloss参数默认增加当前环境,作为expr计算在list/data.frame之外寻找对象定义的闭包。

> eval(res1)
[1] 0.2320291
> eval(res2)
[1] -0.453112
> eval(res3)
[1] 0.09090909

deparse

deparse(expr)

deparse把没有eval的表达式转换成字符串。

> deparse(res1)
[1] "0.141120008059867 + 0.0909090909090909"
> deparse(res2)
[1] "sin(10) + a/b"
> deparse(res3)
[1] "a/b"

call

call(name, ...)
构造一个没有eval的函数调用。第一个参数是函数名(字符串),后面是函数的参数。
举个栗子:

> call_x <- call("+", 7, 8)
> class(call_x)
[1] "call"
> typeof(call_x)
[1] "language"
> eval(call_x)
[1] 15
> deparse(call_x)
[1] "7 + 8"

expressioin

expression(...)
把参数看成表达式,返回expression类型的对象。expression类型和list类型类似,是个容器,每个成员可能是call,symbol(name)和constants中的一种。
若有多个成员,eval每个成员都会求值一遍,但是只返回最后一个成员eval之后的值,这与绝大多数编程语言多个表达式语句(逗号隔开)返回的结果类似。
举个栗子:

> a <- 1
> b <- 2
> c <- 3
> ex1 <- expression(a, 1:10, c <- 10, FALSE)
> sapply(ex1, class)
[1] "name"    "call"    "<-"      "logical"
> sapply(ex1, typeof)
[1] "symbol"   "language" "language" "logical" 
> eval(ex1)
[1] FALSE
> c
[1] 10

parse

parse(text="")
是deparse的逆函数,把表达式字符串解析成为未eval的expression。

> ex1 <- parse(text = "1 + 2 + 3")
> ex1
expression(1 + 2 + 3)
> eval(ex1)
[1] 6

最后一幅图总结这些函数的关系:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值