8

I want to write an R function that takes a mathematical function in x and returns a new function in x as an output. For example:

The input should be passed in as a mathematical function (or relation) in x:

g <- x^2 + 9*x + log(x)

And the resulting output should be:

function(x) (exp(g))

i.e. I want to return the symbolic exponential expression of the original function in x i.e. exp(x^2 + 9*x + log(x)) in this illustrative example

So ideally it would return the function object:

function(x) (exp(x^2 + 9*x + log(x)))

I tried as follows:

test <- function(g){
h <- function(x){exp(g)}
return(h)
}
m <- test(x^2 + 9*x + log(x))
m(10)

So m(10) should return:

exp(10^2 + 9*10 + log(10))

which is exp(192.3026) in this case.

Could anyone show how to do this please?

user4687531
  • 799
  • 11
  • 23
  • this is similar to symbolic differentiation, isn't it? `deriv(expr, ...)` – jogo Dec 09 '15 at 09:22
  • No - no differentiation involved here. Just want to create/ return a new function object (i.e. exp(10^2 + 9*10 + log(10))) from the function that is passed in as an input (i.e. x^2 + 9*x + log(x)). – user4687531 Dec 09 '15 at 09:30
  • because of that I wrote "similar". I know that you want another transformation of the symbolic expression. – jogo Dec 09 '15 at 09:32
  • Sure - in the sense of a functional transformation it is similar - yes – user4687531 Dec 09 '15 at 09:36
  • Yes @JoshO'Brien - you are correct. It is "exp(192.3026)" that I meant. It is now edited thanks! – user4687531 Dec 09 '15 at 09:39

3 Answers3

10

You could use package functional:

library(functional)
fun <- Compose(function(x) x^2 + 9*x + log(x), exp)
fun(1)
#[1] 22026.47
Roland
  • 122,144
  • 10
  • 182
  • 276
  • Please consider editing your post to add more explanation about what your code does and why it will solve the problem. An answer that mostly just contains code (even if it's working) usually wont help the OP to understand their problem. – SuperBiasedMan Dec 09 '15 at 14:56
  • 8
    @SuperBiasedMan Please cease posting these useless comments. – Roland Dec 09 '15 at 15:31
  • 5
    @SuperBiasedMan Please consider using more restraint with review auto-comments. While oftentimes generic comments can be a constructive addition to a Q&A, comments that fail to recognize the difference between code that requires lengthy explanation and code that does not usually won't help improve the content on StackOverflow. ;) – joran Dec 09 '15 at 18:57
7

Here is one approach:

test <- function(e) {
    ee <- substitute(e)
    eee <- substitute(exp(X), list(X=ee))
    f <- function(x) {}
    body(f) <- eee
    environment(f) <- parent.frame()
    f
}

## Check that it works
m <- test(x^2 + 9*x + log(x))
m
# function (x) 
# exp(x^2 + 9 * x + log(x))
m(1)
# [1] 22026.47
m(1) == exp(10)
# [1] TRUE
Josh O'Brien
  • 154,425
  • 26
  • 353
  • 447
  • 1
    For more on building functions programmatically, [see here](http://stackoverflow.com/questions/12982528/how-to-create-an-r-function-programmatically) – Josh O'Brien Dec 09 '15 at 10:01
  • 1
    Please consider editing your post to add more explanation about what your code does and why it will solve the problem. An answer that mostly just contains code (even if it's working) usually wont help the OP to understand their problem. – SuperBiasedMan Dec 09 '15 at 14:56
  • 1
    @SuperBiasedMan -- Please consider pointing specifically to what it is about the code you don't understand and would like help with. Or do you happen to know the OP, and know that answers that contain just code (using common and well-documented functions) won't help them? (In which case, my bad -- could you give me some pointers about how experienced they are as an R user, and perhaps ask them to contact me with their own questions?) – Josh O'Brien Dec 10 '15 at 17:15
3

edit - for functionality in question

f <- function(...) {
  l <- eval(substitute(alist(x = x, ...)))
  l[[2]] <- substitute(exp(X), list(X = l[[2]]))
  as.function(`names<-`(l, l[sapply(l, is.symbol)]))
}

g <- f(x^2 + 2*x + 5)
# function (x = x) 
#   exp(x^2 + 2 * x + 5)

g(1)
# [1] 2980.958

Here is another way for a general case:

f <- function(...) {
  l <- eval(substitute(alist(...)))
  as.function(`names<-`(l, l[sapply(l, is.symbol)]))
}

g <- f(x, x^2 + 9*x + log(x))

# function (x = x) 
#   x^2 + 9 * x + log(x)

g(10)
# [1] 192.3026

This version will also work for any number of variables, just define them followed by the function:

g <- f(x, y, z, x + 2 * y + z ** 3)

# function (x = x, y = y, z = z) 
#   x + 2 * y + z^3

g(1, 2, 0)
# [1] 5

There may be a better way to add ... to functions, but here is how you can do that

f <- function(..., use_dots = FALSE) {
  l <- eval(substitute(alist(...)))
  if (use_dots)
    l <- c(head(l, -1), list('...' = as.symbol('...')), tail(l, 1))
  as.function(`names<-`(l, l[sapply(l, is.symbol)]))
}

So now you don't have to name all the variables/arguments

g <- f(x, y, plot(x, y, ...), use_dots = TRUE)
g(1:5, 1:5, main = 'main title', pch = 16, col = 3, cex = 3, xpd = NA)

enter image description here

rawr
  • 19,873
  • 4
  • 42
  • 74