【问题标题】:How to retrieve formals of a primitive function?如何检索原始函数的形式?
【发布时间】:2014-11-16 16:02:23
【问题描述】:

至少目前,这对我来说是一个学习练习,因此实际功能或其复杂性不是问题。假设我编写了一个函数,其参数列表包括一些输入变量和函数名,作为字符串传递。然后这个函数在内部计算一些变量并“决定”如何将它们提供给我传入的函数名。

对于非原始函数,我可以这样做(对于这个例子,假设我的 funcname 函数没有任何参数,最多 (x,y,z) 除外。如果他们这样做,我必须编写一些代码来搜索匹配names(formals(get(funcname)))以免删除其他参数):

foo <- function (a,b,funcname) {
    x <- 2*a
    y <- a+3*b
     z <- -b
    formals(get(funcname)) <- list(x=x, y=y, z=z)
    bar <- get(funcname)()
return(bar)
}

而且好消息是,即使函数 funcname 不会使用 xyz,它也会毫无错误地执行(只要没有其他 args 不使用) t 有默认值)。
“原始”函数的问题是我不知道有什么方法可以找到或修改它们的形式。除了编写包装器之外,例如foosin &lt;-function(x) sin(x),有没有办法设置我的foo 函数以使用原始和非原始函数名称作为输入参数?

【问题讨论】:

    标签: r


    【解决方案1】:

    根据 Richard S 的回应,我最终做了以下事情。发布以防万一其他人尝试做和我一样奇怪的事情。

    编辑:我认为需要进行更多类型检查。 coleqn 可能是 对象的名称,在这种情况下get(coleqn) 将返回一些数据。可能我需要 在if(!is.null(rab)) 之后添加if(is.function(rab))。 (当然,鉴于我是为自己的需要编写的函数,如果我愚蠢到传递一个对象,我应该得到我得到的 :-))。

    # "coleqn" is the input argument, which is a string that could be either a function
    # name or an expression.
    
    rab<-tryCatch(get(coleqn),error=function(x) {} )
    #oops, rab can easily be neither NULL nor a closure. Damn.
    if(!is.null(rab)) {
    # I believe this means it must be a function
    # thanks to Richard Scriven of SO for this fix to handle primitives
    # we are not allowed to redefine primitive's formals.
        qq <- list(x=x,y=y,z=z) 
    #  matchup the actual formals names
    #  by building a list of valid arguments to pass to do.call 
        argk<-NULL
        argnames<-names(formals(args(coleqn)))
        for(j in 1:length(argnames) )
            argk[j]<-which(names(qq)==argnames[1] )
        arglist<-list()
        for(j in 1:length(qq) ) 
            if(!is.na(argk[j])) arglist[[names(qq)[j]]]<-qq[[j]]
        colvar<- do.call(coleqn,arglist) 
        } else {
    # the input is just an expression (string), not a function
            colvar <- eval(parse(text=coleqn)) 
        } 
    

    结果是由表达式或刚刚创建的函数生成的对象,使用主函数内部的变量(在此 sn-p 中未显示)

    【讨论】:

      【解决方案2】:

      formals(args(FUN)) 可用于获取原始函数的形式。

      您可以在现有函数中添加if 语句。

      > formals(sum)
      # NULL
      > foo2 <- function(x) {
            if(is.primitive(x)) formals(args(x)) else formals(x)
            ## formals(if(is.primitive(x)) args(x) else x) is another option
        }
      > foo2(sum)
      # $...
      #
      #
      # $na.rm
      # [1] FALSE
      #
      > foo2(with)
      # $data
      # 
      #
      # $expr
      #
      #
      # $...
      

      【讨论】:

      • 实际上,formals(args(non_primitive_func)) 返回的内容与 formals(non_primitive_func) 相同。但是我没有想到那个翻倍的事情。谢谢!
      • 是的,但是没有args,它永远不会得到原语的形式。我相信我们可以调整它,以免在代码中重复 formals
      • 更新:不幸的是,这只是成功的一半。我仍然无法像为示例函数重新定义 Primitive 的形式那样重新定义它们的形式。到目前为止,我能想到的最好的方法(对于 Primitives)是检查当前函数 funcname 中存在哪些 x,y,z 并使用该子列表构建一个 do.call
      • @CarlWitthoft - 你确定你真的可以重新定义原语的形式吗?我的印象是这些功能被“锁定”并且无法重新定义。
      • 这就是我的意思:我将创建一个类似arglist=list(x=5,y=3) 的列表,其中仅包含我的输入函数的有效参数名称,然后do.call(get(funcname),arglist) 将工作,只要我没有遗漏任何必要的论据(我认为是我自己的错)。
      猜你喜欢
      • 2023-02-07
      • 1970-01-01
      • 1970-01-01
      • 2015-08-18
      • 2012-02-18
      • 1970-01-01
      • 2021-07-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多