Home > Software engineering >  Using `curve` with a function from a list
Using `curve` with a function from a list

Time:01-05

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?

CodePudding user response:

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 as x.

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
}
  • Related