最近仔细看了下 tidyverse 的一些方法,发现里面大量用到了 quasiquotation 。 每个函数都是个黑盒子,不结合文档完全没法知道该输入什么类型的变量。
于是顺手写了个例子来测试一下。
几乎所有编程语言中符号( Symbol )和字符串( String )是不同的概念,传递一个符号个函数,常理是传递符号后面的变量;而传递一个字符串,传递的是字符串本身。例如这样一个最简单的案例:
f1 <- function(x) {
print(x)
}
x <- "hello"
f1(x)
# [1] hello
f1("x")
# [1] x
但是在 R 语言中,可以用封装出这样一个函数,使得结果和常理完全相背。
f2 <- function(x) {
if (is.name(substitute(x))) {
print(as.character(substitute(x)))
} else {
print(eval(as.name(x), envir = .GlobalEnv))
}
}
x <- "hello"
f2(x)
# [1] x
f2("x")
# [1] hello
导致结果就是软件的开发者可以随心所欲,软件的使用者一脸懵逼。
我想知道这个是不是 R 语言中特有的?其他语言能否也实现这样一个函数,在用户“无感”的情况下,把字符串和符号进行对换?
1
24owls 2020-04-08 17:33:31 +08:00
不要被 R 的语法迷惑,你看到是 LISP 的 MACRO
很多 R 的 Function 并不是 Procedure 或者 Closure,你把它们看作 Macro 就容易看明白了 Macro 过度使用当然是不好的,最好是只有在你想做的事情用其它方法都办不到的情况下再用 |
2
yech1990 OP @24owls 我的感觉是 R 这个 Macro 比 LISP 还玩过了。我没写过 LISP, 不知道 LISP 能不能这么干,但我尝试了下 Julia, 似乎无法实现。
|
3
whoami9894 2020-04-08 22:06:11 +08:00 1
感觉跟语言本身的求值方式有关,函数内可以判断参数是 symbol 还是 literal,而且我试了一下 substitute 能 resolve 到外部调用函数时的 symbol 名称
没写过 R 看不太懂,什么情况下需要 substitute 函数的功能? Lisp 的话,syntax-quote 能做到吗? |
4
yech1990 OP @whoami9894
substitute 在 R 中大量使用,主要是用来实现类似 SQL 语句的效果。例如 python 中的 `df[(df["a"] > 20) & (df["b"] < 40), :]`,在 R 里面可以这么写 `subset(df, a > 20 & b < 47)`。 Lisp 的 syntax-quote 是怎么实现的? |
5
whoami9894 2020-04-09 13:47:50 +08:00
@yech1990 具体的记不太清了,能不能实现 substitute 存疑
这篇文章是用 Clojure 举例的: https://liujiacai.net/blog/2017/10/01/macro-in-action/#syntax-quote-amp-unquote,不同方言的实现也不太一样 |