-2

I have a list of functions and I'd like to me able to call them without them being independent objects. For example:

funcs <- list(foo = function(a, b) a + b,
              ## in a list, how can I call `foo` from `bar`?
              bar = function(m) foo(m, m/2))

I'm looking for something akin to moving up and over in a directory from the current location (e.g. ../foo) but as a function call.

Some context:

There is a package that has some predefined modeling elements. There have been some requests for new features that would require to know the range of parameter values. Those are current encoded in functions in a list. For example, for partial least squares, the parameter values can range between 1 and the number of predictors in the data set:

modelInfo <- list(## other list elements
    grid = function(x, y, len = NULL, search = "grid") {
        if(search == "grid") {
            out <- data.frame(ncomp = seq(1, min(ncol(x) - 1, len), by = 1))
        } else {
            out <- data.frame(ncomp = unique(sample(1:ncol(x), replace = TRUE)))
        } 
        out
    },
    ## more list elements
)

I'd like to add a list element called bounds that will encode the possible values and have grid references them. I could pass in the bounds function data into grid but that would add new arguments and break a lot of backwards compatibility. I didn't think that any other solution would be possible to reference bounds from grid without a significant change in code.

nrussell
  • 18,382
  • 4
  • 47
  • 60
topepo
  • 13,534
  • 3
  • 39
  • 52
  • 2
    What is the actual problem you are trying to solve? This question reads like the [XY problem](http://xyproblem.info/). Lists in R don't create their own environments and functions in R are executed in the environment in which they were created. – MrFlick Sep 03 '16 at 19:05
  • It doesn't make sense to use a list like that. You probably should be using a proper enclosure with proper functions. Your example isn't quite complete or clear enough to test possible solutions. If you made a proper minimal [reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) it would be easier to help and test possible solutions. Why does it **have** to be a list? – MrFlick Sep 03 '16 at 20:43

2 Answers2

2

Instead of a list, use an environment:

env <- new.env()
env$foo <- function(a, b) a + b
env$bar <- function(m) foo(m, m/2)
environment(env$foo) <- environment(env$bar) <- env

env$bar(3)
# 4.5
Hong Ooi
  • 56,353
  • 13
  • 134
  • 187
  • The functions already exist in a package and I'm trying to avoid re-writing everything – topepo Sep 03 '16 at 18:58
  • 2
    ...did you just downvote me for not making use of information you didn't put in your question? – Hong Ooi Sep 03 '16 at 19:01
  • Sorry if that was rude but the question was about how to solve the problem within that data structure (instead of providing a better structure). – topepo Sep 03 '16 at 19:11
2

foo is not on the search path from bar. However, funcs is:

funcs <- list(foo = function(a, b) a + b,
              bar = function(m) funcs$foo(m, m/2))
funcs$bar(3)
#[1] 4.5

If you already have a constructor function, you could do this:

constructFuncs <- function() {
  foo <- function(a, b) a + b 
  bar <- function(m) foo(m, m/2)
  list(foo = foo, bar = bar)
}
funcs <- constructFuncs()
funcs$bar(3)  
#[1] 4.5

However, I recommend using a better approach. Environments (or possibly even reference classes?) seem preferable to lists in this case.

Roland
  • 127,288
  • 10
  • 191
  • 288