简体   繁体   English

R的清洁,简单的功能工厂

[英]Clean, simple function factories in R

Short example. 简短的例子。 I am exploring the behavior of a function by testing it with different "specs", f(spec) . 我正在通过使用不同的“规格” f(spec)测试函数来探索函数的行为。 I wrote down one spec by hand, spec1 , and am creating new specs as variations on it. 我手写了一个规格, spec1 ,并且正在创建新的规格作为它的变体。 To do this, I decided to write a function: 为此,我决定编写一个函数:

spec1 = list(fy = list(a = 1), fx = list(f1 = function(x) 10-x, f2 = function(x) 2-x))

make_spec = function(f = function(x) 10-x, xtheta = 2)
    list(fy = list(a = 1), fx = list(f1 = f, f2 = function(x) xtheta-x))

res1 = make_spec()

# first problem: they don't match

    all.equal(res1,spec1)
    # [1] "Component “fx”: Component “f2”: target, current do not match when deparsed"
    # ^ this happens, even though...
    res1$fx$f2(4) == spec1$fx$f2(4)
    # TRUE

# second problem: res1 is fugly

    res1
    # $fy
    # $fy$a
    # [1] 1
    # 
    # 
    # $fx
    # $fx$f1
    # function (x) 
    # 10 - x
    # <environment: 0x000000000f8f2e20>
    # 
    # $fx$f2
    # function (x) 
    # xtheta - x
    # <environment: 0x000000000f8f2e20>

    str(res1)
    # even worse

My goals for make_spec are... 我对make_spec目标是......

  1. all.equal(spec1, res1) and/or identical(spec1, res1) all.equal(spec1, res1)和/或identical(spec1, res1)
  2. for str(res1) to be human-readable (no <environment: ptr> tags or srcfilecopy ) for str(res1)是人类可读的(没有<environment: ptr>标签或srcfilecopy
  3. to avoid substitute and eval altogether if possible (not a high priority) 尽可能避免substituteeval (不是高优先级)
  4. to avoid writing out the second arg of substitute (see "full" example below) 避免写出substitute的第二个arg(参见下面的“完整”示例)

Is there an idiomatic way to achieve some or all of these goals? 是否有一种惯用的方式来实现这些目标中的一些或全部?


Full example. 完整的例子。 I'm not sure if the example above fully covers my use case, so here's the latter: 我不确定上面的例子是否完全覆盖了我的用例,所以这是后者:

spec0 = list(
    v_dist = list(
        pdf  = function(x) 1,
        cdf  = function(x) x,
        q    = function(x) x,
        supp = c(0,1)
    )
    ,
    ucondv_dist = {
        ucondv_dist = list()
        ucondv_dist$condmean    = function(v) 10-v
        ucondv_dist$pdf         = function(u,v) dnorm(u, ucondv_dist$condmean(v), 50)
        ucondv_dist$cdf         = function(u,v) pnorm(u, ucondv_dist$condmean(v), 50)
        ucondv_dist
    }
)

make_spec = function(ycondx_condmean = function(x) 10-x, ycondx_sd = 50){

  s = substitute(list(
    x_dist = list(
      pdf  = function(x) 1,
      cdf  = function(x) x,
      q  = function(x) x,
      supp = c(0,1)
    )
    ,
    ycondx_dist = {
      ycondx_dist = list()
      ycondx_dist$condmean  = ycondx_condmean
      ycondx_dist$pdf     = function(u,v) dnorm(u, ycondx_dist$condmean(v), ycondx_sd)
      ycondx_dist$cdf     = function(u,v) pnorm(u, ycondx_dist$condmean(v), ycondx_sd)
      ycondx_dist
    }
  )
  , list(ycondx_condmean=ycondx_condmean, ycondx_sd = ycondx_sd))

  eval(s, .GlobalEnv)
}

res0 = make_spec()

Side note . 旁注 I don't know if "function factory" is the right term here, since I am not a computer scientist, but it seems related. 我不知道“功能工厂”这里是否是正确的术语,因为我不是计算机科学家,但它似乎有关系。 I found only a paragraph on the concept related to R . 在与R相关的概念中只找到了一个段落

The enclosing environments of the functions are different leading to the difference in output/difference in deparsing. 功能的封闭环境不同,导致脱落的输出/差异不同。 So, there are two things to do to get the desired output: 因此,要获得所需的输出,有两件事要做:

  • make the environments the same 使环境相同
  • substitute the variables from the enclosing environments into the function bodies. 将封闭环境中的变量替换为函数体。

However, doing it this way you get a double dose of the eval/substitute you didn't want, so maybe there would be an alternative. 然而,这样做你得到双倍剂量的你不想要的eval /替代品,所以也许会有另一种选择。

make_spec <- function(f = function(x) 10-x, xtheta = 2) {
  e <- parent.frame()
  fixClosure <- function(func)
    eval(eval(substitute(substitute(func)), parent.frame()), e)

  list(fy = list(a = 1), fx = list(
    f1 = fixClosure(f), 
    f2 = fixClosure(function(x) xtheta-x)
  ))
}

spec1 <- list(fy = list(a = 1), fx = list(f1 = function(x) 10-x, f2 = function(x) 2-x))
res1 <- make_spec()

all.equal(res1, spec1)
[1] TRUE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM