0

In a for loop I make a "string-formula" and allocate it to e.g. body1. And when I try to make a function with that body1 it fails... And I have no clue what I should try else...

This question How to create an R function programmatically? helped me a lot but sadly only quote is used to set the body...

I hope you have an idea how to work around with this issue.

And now my code:

A.m=matrix(c(3,4,2,2,1,1,1,3,2),ncol=3,byrow=TRUE)

for(i in 1:dim(A.m)[1]) {

    body=character()

    # here the string-formula emerges
    for(l in 1:dim(A.m)[2]) {   
        body=paste0(body,"A.m[",i,",",l,"]","*x[",l,"]+")
    }

    # only the last plus-sign is cutted off
    assign(paste0("body",i),substr(body,1,nchar(body)-1))
}


args=alist(x = )

# just for your convenience the console output
body1
## [1] "A.m[1,1]*x[1]+A.m[1,2]*x[2]+A.m[1,3]*x[3]"

# in this code-line I don't know how to pass body1 in feasible way
assign("Function_1", as.function(c(args, ???body1???), env = parent.frame())

And this is my aim:

Function_1(x=c(1,1,1))
## 9 # 3*1 + 4*1 + 2*1
tueftla
  • 369
  • 1
  • 3
  • 16

1 Answers1

3

Since you have a string, you need to parse that string. You can do

assign("Function_1", 
  as.function(c(args, parse(text=body1)[[1]])), 
  env = parent.frame())

Though I would strongly discourage the use of assign for filling your global environment with a bunch of variables with indexes in their name. In general that makes things much tougher to program with. It would be much easier to collect all your functions in a list. For example

funs <- lapply(1:dim(A.m)[1], function(i) {
  body <- ""
  for(l in 1:dim(A.m)[2]) {   
    body <- paste0(body,"A.m[",i,",",l,"]","*x[",l,"]+")
  }
  body <- substr(body,1,nchar(body)-1)
  body <- parse(text=body)[[1]]
  as.function(c(alist(x=), body), env=parent.frame())
})

And then you can call the different functions by extracting them with [[]]

funs[[1]](x=c(1,1,1))
# [1] 9
funs[[2]](x=c(1,1,1))
# [1] 4

Or you can ever call all the functions with an lapply

lapply(funs, function(f, ...) f(...), x=c(1,1,1))
# [[1]]
# [1] 9
# [[2]]
# [1] 4
# [[3]]
# [1] 6

Although if this is actually what your function is doing, there are easier ways to do this in R using matrix multiplication %*%. Your Function_1 is the same as A.m[1,] %*% c(1,1,1). You could make a generator funciton like

colmult <- function(mat, row) {
  function(x) {
    as.numeric(mat[row,] %*% x)
  }
}

And then create the same list of functions with

funs <- lapply(1:3, function(i) colmult(A.m, i))

Then you don't need any string building or parsing which tends to be error prone.

MrFlick
  • 195,160
  • 17
  • 277
  • 295
  • I also tried `parse()` but without the `[[1]]`... so thanks a lot. Especially for the hint to do the generated functions in a list for better handling. – tueftla Jul 01 '21 at 08:32