A colleague asked me this, and I have struggled with it.
Suppose I want to define a function that takes an expression (let's say x^2
for concreteness) as an argument and passes that argument to curve()
.
If I want to do this the easy way, I just run
curve(x^2,from=0,to=3)
and it works fine.
Suppose I try to set up a wrapper function (let's say there are other things I want to do inside the wrapper in addition to plotting the curve):
f <- function(g) {
curve(g,from=0,to=3)
}
This works if I pass a function:
f(function(x) x^2)
it fails if I try to pass x^2
, when R tries to evaluate the expression:
f(x^2)
## Error in eval(expr, envir, enclos) (from #2) : object 'x' not found
I can try to forestall this by using substitute
within the function:
f0 <- function(g) {
str(substitute(g))
curve(substitute(g),from=0,to=3)
}
f0(x^2)
## language x^2
## Error in curve(substitute(g), from = 0, to = 3) (from #3) :
## 'expr' must be a function, or a call or an expression containing 'x'
OK, that suggests maybe I should try
f <- function(g) {
h <- as.expression(substitute(g))
str(h)
curve(as.expression(substitute(g)),from=0,to=3)
}
f(x^2)
## expression(x^2)
## Error in curve(as.expression(substitute(g)), from = 0, to = 3) (from #4) :
## 'expr' must be a function, or a call or an expression containing 'x'
For what it's worth,
curve(h,...)
("function h
not found")as.call()
is substituted for as.expression()
curve()
doesn't work on expressions in any case:curve(expression(x^2),from=0,to=1)
## Error in curve(expression(x^2), from = 0, to = 1) :
## 'expr' did not evaluate to an object of length 'n'
If I try debugging curve()
to see what's happening, we have:
sexpr <- substitute(expr)
...
if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in%
all.vars(sexpr)))
stop(...)
Here sexpr
is substitute(g)
, which fails the xname %in% all.vars(sexpr)
test ...
Any ideas about how to handle this?
I didn't mean to ask-and-then-answer, but I figured out the (an?) answer with a little bit more poking around -- it occurred to me that I hadn't tried eval
yet. eval(curve(substitute(g),from=0,to=3))
does not work, but this does:
f1 <- function(g) {
eval(substitute(curve(g,from=0,to=3)))
}
f1(x^2)
update: @RichardScriven suggests that do.call()
might work too -- and it does!
f2 <- function(g) {
do.call(curve,list(substitute(g),from=0,to=3))
}
f2(x^2)
Further explication is welcome!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With