9

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?

5
  • this is similar to symbolic differentiation, isn't it? deriv(expr, ...) Commented Dec 9, 2015 at 9: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)). Commented Dec 9, 2015 at 9:30
  • because of that I wrote "similar". I know that you want another transformation of the symbolic expression. Commented Dec 9, 2015 at 9:32
  • Sure - in the sense of a functional transformation it is similar - yes Commented Dec 9, 2015 at 9:36
  • Yes @JoshO'Brien - you are correct. It is "exp(192.3026)" that I meant. It is now edited thanks! Commented Dec 9, 2015 at 9:39

3 Answers 3

10

You could use package functional:

library(functional)
fun <- Compose(function(x) x^2 + 9*x + log(x), exp)
fun(1)
#[1] 22026.47
Sign up to request clarification or add additional context in comments.

3 Comments

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 Please cease posting these useless comments.
@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. ;)
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

3 Comments

For more on building functions programmatically, see here
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 -- 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?)
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

6 Comments

Thanks. I tried the following for my application but didn't quite work: f <- function(...) { l <- eval(substitute(alist(...))) as.function(names<-(l, l[sapply(l, is.symbol)])) } test2 <- function(g){ # Create the function h(x) which is a function # of the g(x) input function passed in as a string h <- f(x, exp(g)) return(h) } y <- test2(x^2 + 2*x) y(10) y_prime <- D(body(y), 'x') y_prime
I wanted to return the exp(function) and then take its derivative. Could you please assist as this method seems concise and useful if I can get it to work
@user4687531 change the g to x and it will work. the variables need to match, otherwise the function doesn't know what to use, for example test2 <- function(x) f(x, exp(x))
I don't believe that works as intended. If I do y <- test2(x^2 + 2*x + 5). I expect the y to equal exp(x^2 + 2*x + 5). It currently evaluates to exp(x). Could you pls show how to adapt your code to do this by adapting my code in the comment above?
@user4687531 see edit. it was intended that you do that in the first version via g <- f(x, exp(x^2 + 9*x + log(x))) but I left of the exp. since your desired function is always to use exp, this is a little less general and needs a special case to handle as in the edit, so now using that version of f, you can simply do g <- f(x^2 + 9*x + log(x)) as expected. I mean less general because this function will only have one variable, x, and will only be of the form exp(...) where ... is whatever you pass to f
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.