如何检查R中的函数是否是常量函数?

pat*_*_ai 16 r constants function

一个R函数传递给我,它在Real Line的某个区间定义并返回一个数值.有没有办法检查功能是否恒定?

示例功能:

f1<-function(x) {11}
f2<-function(x) {x+2}
f3<-function(x) {1+1}
f4<-function(x) {return(3)}
Run Code Online (Sandbox Code Playgroud)

我正在寻找一个测试,它会说f1,f3,f4是常数函数,但f2不是.有任何想法吗?

编辑:

弗兰克和格雷戈尔(编辑:和迈克尔劳伦斯的第二个解决方案)以下解决方案都适用于上面给出的所有4个测试用例(Marat和迈克尔不对所有4个案例都有效).所以已有解决方案.但是,如果您能找到一个解决方案,并为以下3个测试功能提供正确的答案,那么额外的奖励积分:

f5 <- function(x) ifelse(x == 5.46512616432116, 0, 1)
f6 <- function(x) ifelse(x == 5.46512616432116, 0, 0)
f7 <- function(x) {x - x}
Run Code Online (Sandbox Code Playgroud)

Mar*_*pov 11

试试functionBody:

> is.numeric(functionBody(f1)[[2]])
[1] TRUE

> is.numeric(functionBody(f2)[[2]])
[1] FALSE
Run Code Online (Sandbox Code Playgroud)

  • 一旦有函数调用,所有投注都会关闭.这个答案容易解决的问题是它需要很强大才能没有`{`.更好的检查是`!is.language()`而不是`is.numeric()`. (4认同)
  • @bisounours_tronconneuse - 因为这在技术上是一个函数调用,而不是常量.这取决于另一个变量:) (3认同)

Fra*_*ank 5

此函数测试参数f是否用作数字:

is_using_argasnumber <- function(f) 
  grepl("non-numeric argument",try(f("Hello World!"),silent=TRUE))
Run Code Online (Sandbox Code Playgroud)

例子:

is_using_argasnumber(function(x)1+1)        # FALSE
is_using_argasnumber(function(x)"guffaw")   # FALSE
is_using_argasnumber(function(x)sqrt(x+2))  # TRUE
Run Code Online (Sandbox Code Playgroud)

如果你需要测试数学函数是否是常数,你需要特殊的工具来理解并简化公式.


概论.

  • 它对具有多个参数的函数没有意义.
  • 如果使用R的不同本地化,...
    • 我建议替换或添加正则表达式,例如,使用"(non-numeric argument)|(argument non numérique)".不幸的是,据我所知,R不使用或公开"错误代码",这将允许语言不变的解释try结果.
    • OP提出的替代方案是简单地检查是否存在任何错误,但我认为如果被测试的函数有任何错误可能会产生太多的误报:

.

is_breaking_withargascharacter <- function(f)
  inherits(try(f("Hello World!"),silent=TRUE),'try-error')
Run Code Online (Sandbox Code Playgroud)


Gre*_*gor 5

这些基于代码的测试很聪明,很有趣,但到目前为止,我认为"尝试一堆数字"的方法可能是一个更强大的测试,取决于你可能获得的函数类型以及你是否更关心Type I或您的身份证明中的II型错误.

在你的问题中,你说

它是在Real Line的某个区间定义的

所以我们假设我们知道感兴趣的领域.在该域上采样一些点,并测试您的功能.

n = 1e5
test = runif(n, min = 0, max = 5)
results = f(test) # sapply(test, f) if f isn't vectorized

# test for constancy
all(results == results[1]) # or all(diff(results) == 0) or however else
Run Code Online (Sandbox Code Playgroud)

任何真正是常数函数的函数都会通过这个测试,无论多么病态 - 对于目前为止建议的任何其他方法都不会这样.但是,使用我在评论中留下的示例(或任何此类内容)来愚弄测试很容易

f3 = function(x) ifelse(x == 5.46512616432116, 0, 1)
Run Code Online (Sandbox Code Playgroud)

  • 并且,如果函数不是以某种方式"随机"生成的,那么也很容易检查"特殊"值,如果它包含在域中,则检查0,或者检查`pretty(mydomain)`中的值. (2认同)

Mic*_*nce 5

这可以处理显式return,缺失{甚至空的情况{ }:

evaluatesToConstant <- function(b) {
    if (is(b, "{")) {
        if (length(b) > 2L)
            return(FALSE)
        if (length(b) == 1L)
            last <- NULL
        else last <- b[[2L]]
    } else {
        last <- b
    }
    if (is.call(last) && last[[1L]] == quote(return)) {
        last <- last[[2L]]
    }
    !is.language(last)
}
evaluatesToConstant(functionBody(fun))
Run Code Online (Sandbox Code Playgroud)

这是另一种非常聪明的方法,但它可以被欺骗.假设给定常量参数,它将假定任何原始函数将返回相同的值.只要符号在函数内定义,它也允许使用符号.但由于符号可以在定义之前引用,也可以在嵌套范围内定义,因此启发式不安全.无论如何,这里是:

evaluatesToConstant <- function(expr, allowDefinitions=FALSE) {
    vars <- all.vars(expr)
    calls <- setdiff(all.names(expr), vars)
    funs <- mget(calls, parent.frame(), mode="function", inherits=TRUE)
    defined <- if (allowDefinitions)
                   rapply(as.list(expr),
                          function(x) as.character(substitute(x)[[2L]]), "<-",
                          how="unlist")
    length(setdiff(vars, defined)) == 0L &&
        all(vapply(funs, is.primitive, logical(1L)))
}
Run Code Online (Sandbox Code Playgroud)

应该是TRUE:

evaluatesToConstant(functionBody(function(x) { foo <- 1 + 1; foo }), TRUE)
Run Code Online (Sandbox Code Playgroud)