【问题标题】:rlang: Error: Can't convert a function to a stringrlang:错误:无法将函数转换为字符串
【发布时间】:2019-12-21 07:48:09
【问题描述】:

我创建了一个函数来将函数名转换为字符串。版本 1 func_to_string1 运行良好,但版本 2 func_to_string2 不起作用。

func_to_string1 <- function(fun){
    print(rlang::as_string(rlang::enexpr(fun)))
}

func_to_string2 <- function(fun){
    is.function(fun)
    print(rlang::as_string(rlang::enexpr(fun)))
}

func_to_string1 工作:

> func_to_string1(sum)
[1] "sum"

func_to_string2 不起作用。

> func_to_string2(sum)
 Error: Can't convert a primitive function to a string
Call `rlang::last_error()` to see a backtrace 

我的猜测是,通过在将 fun 转换为字符串之前调用它,它会在函数内部进行评估并因此抛出错误消息。但是,我没有做任何作业,为什么会发生这种情况呢?

我的问题是为什么会发生这种情况,有没有更好的方法将函数名转换为字符串?

感谢任何帮助,谢谢!

【问题讨论】:

    标签: r rlang tidyeval


    【解决方案1】:

    这不是一个完整的答案,但我认为它不适合评论。

    R 有一种称为 pass-by-promise 的机制, 因此,函数的形式参数是惰性对象(promise),只有在使用时才会被评估。 即使你没有执行任何任务, 对is.function 的调用使用参数, 因此,promise 被评估的结果“替换”。

    不过,在我看来,这似乎与rlang* 不一致, 特别是考虑到科里的回答, 这意味着即使在使用给定参数之后,R 仍然可以找到 promise 对象; 这样做的机制可能不是 R 的公共 API 的一部分。

    *编辑:见评论。

    无论如何,您可以将enexpr/enquo/ensym 视为base::missing, 从某种意义上说,您应该只将它们与您在函数体中根本没有使用过的参数一起使用。

    【讨论】:

    • 这不是 rlang 中的不一致。一旦一个承诺被强制执行,它就不再有一个环境,这意味着我们不能从它创建一个 quosure。我们决定让enexpr()enquo() 保持一致。
    • 如果您不需要 quasiquotation 或 quosure,那么使用 substitute() 是有意义的。
    • @LionelHenry 我明白了,我想这是有道理的,尽管文档可能更具体,因为它确实说 enexpr 对应于 substitute,但 enexpr 可以返回非表达式,如果给定的承诺已经被评估。此外,在快速测试中,enquo 确实创建了一个 quosure,尽管环境为空。
    • 在某些情况下,substitute() 也可能返回非表达式,因为字节码编译器会从 Promise 中解开常量。
    【解决方案2】:

    也许改用这个?

    func_to_string2 <- function(fun){
      is.function(fun)
      deparse(substitute(fun)) 
      #print(rlang::as_string(rlang::enexpr(fun)))
    }
    > func_to_string2(sum)
    [1] "sum"
    

    【讨论】:

      【解决方案3】:

      这个问题提出了一个关于惰性评估的有趣观点。

      R 参数是惰性求值的,这意味着直到需要时才对参数进行求值。

      这在 Advanced R 书中得到了最好的理解,其中包含以下示例,

      f <- function(x) {
        10
      }
      f(stop("This is an error!"))
      

      结果是 10,这令人惊讶,因为 x 从未被调用,因此从未被评估。我们可以通过使用force()来强制评估x

      f <- function(x) {
        force(x)
        10
      }
      f(stop("This is an error!"))
      

      这符合预期。事实上,我们甚至不需要force()(虽然明确一点很好)。

      f <- function(x) {
        x
        10
      }
      f(stop("This is an error!"))
      

      这就是你在这里的电话所发生的事情。函数sum 最初是一个符号,当is.function() 被调用时,它在没有参数的情况下被评估。事实上,即使这样也会失败。

      func_to_string2 <- function(fun){
        fun
        print(rlang::as_string(rlang::ensym(fun)))
      }
      

      总的来说,我认为最好在函数的开头使用enexpr()

      来源:

      http://adv-r.had.co.nz/Functions.html

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-07
        • 2019-08-31
        相关资源
        最近更新 更多