rlang: Error: Can't convert a function to a string

霸气de小男生 提交于 2021-01-27 10:47:30

问题


I created a function to convert a function name to string. Version 1 func_to_string1 works well, but version 2 func_to_string2 doesn't work.

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 works:

> func_to_string1(sum)
[1] "sum"

func_to_string2 doesn't work.

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

My guess is that by calling the fun before converting it to a string, it gets evaluated inside function and hence throw the error message. But why does this happen since I didn't do any assignments?

My questions are why does it happen and is there a better way to convert function name to string?

Any help is appreciated, thanks!


回答1:


This isn't a complete answer, but I don't think it fits in a comment.

R has a mechanism called pass-by-promise, whereby a function's formal arguments are lazy objects (promises) that only get evaluated when they are used. Even if you didn't perform any assignment, the call to is.function uses the argument, so the promise is "replaced" by the result of evaluating it.

Nevertheless, in my opinion, this seems like an inconsistency in rlang*, especially given cory's answer, which implies that R can still find the promise object even after a given parameter has been used; the mechanism to do so might not be part of R's public API though.

*EDIT: see coments.

Regardless, you could treat enexpr/enquo/ensym like base::missing, in the sense that you should only use them with parameters you haven't used at all in the function's body.




回答2:


Maybe use this instead?

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:


This question brings up an interesting point on lazy evaluations.

R arguments are lazily evaluated, meaning the arguments are not evaluated until its required.

This is best understood in the Advanced R book which has the following example,

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

the result is 10, which is surprising because x is never called and hence never evaluated. We can force x to be evaluated by using force()

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

This behaves as expected. In fact we dont even need force() (Although it is good to be explicit).

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

This what is happening with your call here. The function sum which is a symbol initially is being evaluated with no arguments when is.function() is being called. In fact, even this will fail.

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

Overall, I think its best to use enexpr() at the very beginning of the function.

Source:

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



来源:https://stackoverflow.com/questions/57500016/rlang-error-cant-convert-a-function-to-a-string

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!