吐槽一下 R 语言的“魔法”,顺便请教一下元编程在其他语言中的实现。

2020-04-08 17:17:54 +08:00
 yech1990

最近仔细看了下 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 语言中特有的?其他语言能否也实现这样一个函数,在用户“无感”的情况下,把字符串和符号进行对换?

2254 次点击
所在节点    程序员
5 条回复
24owls
2020-04-08 17:33:31 +08:00
不要被 R 的语法迷惑,你看到是 LISP 的 MACRO

很多 R 的 Function 并不是 Procedure 或者 Closure,你把它们看作 Macro 就容易看明白了

Macro 过度使用当然是不好的,最好是只有在你想做的事情用其它方法都办不到的情况下再用
yech1990
2020-04-08 17:39:34 +08:00
@24owls 我的感觉是 R 这个 Macro 比 LISP 还玩过了。我没写过 LISP, 不知道 LISP 能不能这么干,但我尝试了下 Julia, 似乎无法实现。
whoami9894
2020-04-08 22:06:11 +08:00
感觉跟语言本身的求值方式有关,函数内可以判断参数是 symbol 还是 literal,而且我试了一下 substitute 能 resolve 到外部调用函数时的 symbol 名称
没写过 R 看不太懂,什么情况下需要 substitute 函数的功能? Lisp 的话,syntax-quote 能做到吗?
yech1990
2020-04-09 02:46:01 +08:00
@whoami9894
substitute 在 R 中大量使用,主要是用来实现类似 SQL 语句的效果。例如 python 中的 `df[(df["a"] > 20) & (df["b"] < 40), :]`,在 R 里面可以这么写 `subset(df, a > 20 & b < 47)`。

Lisp 的 syntax-quote 是怎么实现的?
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,不同方言的实现也不太一样

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/660514

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX