V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yech1990
V2EX  ›  程序员

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

  •  
  •   yech1990 · 2020-04-08 17:17:54 +08:00 · 2250 次点击
    这是一个创建于 1478 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

    5 条回复    2020-04-09 13:47:50 +08:00
    24owls
        1
    24owls  
       2020-04-08 17:33:31 +08:00
    不要被 R 的语法迷惑,你看到是 LISP 的 MACRO

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

    Macro 过度使用当然是不好的,最好是只有在你想做的事情用其它方法都办不到的情况下再用
    yech1990
        2
    yech1990  
    OP
       2020-04-08 17:39:34 +08:00
    @24owls 我的感觉是 R 这个 Macro 比 LISP 还玩过了。我没写过 LISP, 不知道 LISP 能不能这么干,但我尝试了下 Julia, 似乎无法实现。
    whoami9894
        3
    whoami9894  
       2020-04-08 22:06:11 +08:00   ❤️ 1
    感觉跟语言本身的求值方式有关,函数内可以判断参数是 symbol 还是 literal,而且我试了一下 substitute 能 resolve 到外部调用函数时的 symbol 名称
    没写过 R 看不太懂,什么情况下需要 substitute 函数的功能? Lisp 的话,syntax-quote 能做到吗?
    yech1990
        4
    yech1990  
    OP
       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
        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,不同方言的实现也不太一样
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   989 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 20:51 · PVG 04:51 · LAX 13:51 · JFK 16:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.