Why does curve
not seem to work with elements extracted from a list?
Consider two seemingly identical functions, but built differently:
a <- function(value){
function(x) x + value
}
m <- lapply(1:3, a)
f <- a(1)
all.equal(f, m[[1]])
#[1] TRUE
curve
works for f
, but not m[[1]]
:
> curve(m[[1]])
Error in curve(m[[1]]) :
'expr' must be a function, or a call or an expression containing 'x'
But it works if the object is extracted before:
d <- m[[1]]
curve(d)
Is there a reason for it?
curve()
is a "magic" function that tries to interpret its input as an expression when possible; it doesn't always work.
@user2554330 comments that curve()
is expecting (from ?curve
):
The name of a function, or a call or an expression written as a function of
x
which will evaluate to an object of the same length asx
.
Instead, m[[1]]
is an expression that evaluates to a function. In contrast, d
is the name of a function. You can get what you want using curve(m[[1]](x))
which makes the input an expression written as a function of x.
In the code below, R looks at the expression passed to curve()
and asks whether is.name(sexpr)
is TRUE. This test passes for f
but fails for m[[1]]
(if you want to test it outside of the function context, you need to compare is.name(quote(f))
and is.name(quote(m[[1]])
).
Weirdly enough, plot(m[[1]])
does work (it calls plot.function()
, which calls curve()
with different arguments internally).
sexpr <- substitute(expr)
if (is.name(sexpr)) {
expr <- call(as.character(sexpr), as.name(xname))
}
else {
if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in%
all.vars(sexpr)))
stop(gettextf("'expr' must be a function, or a call or an expression containing '%s'",
xname), domain = NA)
expr <- sexpr
}