如何测试变量是否包含 lambda 函数?

How to test if a variable holds a lambda-function?

我正在构建一个主要参数可以是各种事物的函数,例如公式、函数或 lambda 函数,它必须相应地处理事情。

library(rlang)
my_func=function(x){
    if(is_function(x))
        return("X is a function")
    else if(is_lambda(x))
        return("X is a lambda")
    else if(is_formula(x))
        return("X is a formula")
    else 
        return("X is something else")
}
my_func(x=is.numeric) #function
my_func(x=A~B) #formula
my_func(x=~is.numeric(.x)) #formula too :'(
my_func(x="foo") #something else

如您所见,rlang::is_lambda 无法识别 lambda 函数。在帮助文件示例中,他们首先使用 as_function (is_lambda(as_function(x))),但是当 x 不是 lambda 函数公式时会引发转换错误。如果可能,我宁愿不使用 trycatch,因为我发现它有时会导致不可读的代码和隐藏的错误。

如何简单地测试这个案例?

您可以解析公式并测试其第一个字符是否为波浪号。这意味着任何没有左手边的公式都可以被强制转换为 lambda,但我猜这无论如何都是理想的行为。

library(rlang)

my_func=function(x){
    if(is_function(x))
        return("X is a function")
    else if(is_formula(x)){
        if(substr(deparse(x), 1, 1) ==  "~"){
            if(is_lambda(as_function(x))) 
                return("X is a lambda")
        }
        return("X is a formula")
    }
    else 
        return("X is something else")
}

my_func(x=is.numeric)
#> [1] "X is a function"
my_func(x=A~B) 
#> [1] "X is a formula"
my_func(x=~is.numeric(.x)) 
#> [1] "X is a lambda"
my_func(x="foo") 
#> [1] "X is something else"

reprex package (v0.3.0)

于 2020-03-16 创建

虽然 Allan 的回答很好,但我决定坚持 rlang 所做的。

如果您查看 View(rlang::as_function),您会发现它仅中止 if (length(x) > 2)

因此,我的代码可以写成:

library(rlang)
my_func=function(x){
  if(is_function(x))
    return("X is a function")
  else if(is_formula(x)){
    if(length(x) > 2)
      return("X is a formula")
    else if(is_lambda(as_function(x)))
      return("X is a lambda")
  }
  return("X is something else")
}

这每次都会 return 预期的输出。