Clean, simple function factories in R

Viewed 335

Short example. I am exploring the behavior of a function by testing it with different "specs", f(spec). I wrote down one spec by hand, spec1, and am creating new specs as variations on it. 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...

  1. all.equal(spec1, res1) and/or identical(spec1, res1)
  2. for str(res1) to be human-readable (no <environment: ptr> tags or srcfilecopy)
  3. to avoid substitute and eval altogether if possible (not a high priority)
  4. to avoid writing out the second arg of substitute (see "full" example below)

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.

1 Answers
Related