user4687531
user4687531

Reputation: 1111

Create list of functions without eval/parse

I have 3 vectors of equal length y, h and hp defined as follows:

y  <- c(2, 5, 6)
h  <- c(4, 25, 35)
hp <- c(3, 10, 12)

The values are simply illustrative.

I want to create an output list final_list of functions in x as follows

function(x) y + (h - hp) * x

(only ideal illustrative output shown):

[[1]]
[1] function(x) 2 + (1) * x

[[2]]
[1] function(x) 5 + (15) * x

[[3]]
[1] function(x) 6 + (23) * x

I am aware that this can be done with eval/parse, but this does not produce transparent output for the functions.

I would like to create the functions from these 3 vectors and output without using eval/parse. If this is possible I would be really happy to learn and be impressed!

Upvotes: 5

Views: 145

Answers (3)

IRTFM
IRTFM

Reputation: 263352

Just using the function-function will succeed if it is executed in the correct environment.

> mapply( function(y,h,hp) function(x){ y+(h-hp)*x }, y,h,hp)
[[1]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x7fb570828710>

[[2]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x7fb570823718>

[[3]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x7fb57081b5c8>


> myfuns[[1]](x=1:10)
 [1]  3  4  5  6  7  8  9 10 11 12
> 2+(h[1]-hp[1])*1:10
 [1]  3  4  5  6  7  8  9 10 11 12

> myfuns[[2]](x=1:10)
 [1]  20  35  50  65  80  95 110 125 140 155

Each of those function definitions (actually closures) carries along the first matching values that existed at the time of its creation when the interpreted traveled along the search path.

> environment(myfuns[[1]])[["y"]]
[1] 2
> environment(myfuns[[1]])[["h"]]
[1] 4
> environment(myfuns[[1]])[["hp"]]
[1] 3

Upvotes: 3

Rich Scriven
Rich Scriven

Reputation: 99331

You can use Map() with substitute(). The middle expressions are not yet evaluated, but I don't think that's such a big deal. They will be evaluated when the functions are called. Basically we just assemble the function in parts.

funs <- Map(
    function(a, b, c) {
        f <- function(x) x
        body(f) <- substitute(y + (h - hp) * x, list(y = a, h = b, hp = c))
        f
    }, 
    a = y, b = h, c = hp
)

funs
# [[1]]
# function (x) 
# 2 + (4 - 3) * x
# <environment: 0x4543fd0>
#
# [[2]]
# function (x) 
# 5 + (25 - 10) * x
# <environment: 0x4549e20>
#
# [[3]]
# function (x) 
# 6 + (35 - 12) * x
# <environment: 0x454e5d8>

Now let's call the functions -

sapply(funs, function(a) a(1))
# [1]  3 20 29

Note: If you really need those middle expressions evaluated in the function bodies, you can use the following instead.

make <- function(a, b, c) {
    d <- b - c
    f <- function(x) x
    body(f) <- substitute(y + (e) * x, list(y = a, e = d))
    f
}

funs <- Map(make, y, h, hp)

Upvotes: 5

Dason
Dason

Reputation: 61933

y <- c(2,5,6)
h <- c(4, 25, 35)
hp <- c(3, 10, 12)
fun_create <- function(y, h, hp){
  fun <- function(x){y + (h - hp)*x}
  return(fun)
}
out <- mapply(y, h, hp, FUN = fun_create)

The output doesn't give what you might expect but it works correctly:

> out
[[1]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x282ee40>

[[2]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x282e610>

[[3]]
function (x) 
{
    y + (h - hp) * x
}
<environment: 0x282dde0>

> out[[1]](1)
[1] 3

Upvotes: 5

Related Questions