I am trying to understand the R expression
object, but encountered some difficulties.
Code snippet:
a = 1
b = 2
x = expression(sin(a+b+1))
print(class(x[[1]][2]))
eval(x[[1]][2])
Results:
#////////////////////////////////////////////////////
x = expression(sin(a+b+1))
#////////////////////////////////////////////////////
print(class(x[[1]][2]))
[1] "call"
#////////////////////////////////////////////////////
x = expression(sin(a+b+1))
#////////////////////////////////////////////////////
print(class(x[[1]][2]))
[1] "call"
#////////////////////////////////////////////////////
eval(x[[1]][2])
Error in eval(expr, envir, enclos) : attempt to apply non-function
2: eval(expr, envir, enclos)
1: eval(x[[1]][2])
x[[1]][2]
is a call
object, but why can't it be evaluated?
You should use the [[
operator, and not the [
.
a <- 1
b <- 2
eval(x[[1]][[2]])
## [1] 4
This is because you'd like to extract information from the language object, and not to subset it (look inside the 2nd element, and not return a subsequence consisting of the 2nd element).
In other words, subsetting a call
gives you a call
:
x[[1]][2]
## (a + b + 1)()
and because there is no such function as a+b+1
(in fact, the result of a+b+1
's evaluation is not a function object), R throws an error.
Interestingly, if +
would return a function object, this could make sense:
"+" <- function(a, b) { function() print(":-)") }
(a+b+1)()
[1] ":-)"
On the other hand, extracting an element from a call object gives you an expression that can be evaluated:
x[[1]][[2]]
a + b + 1
(BTW, this expression is also a call, here equivalent to "+"(a, "+"(b, 1))
.
EDIT. More formally, a call is an expression (sequence) of the form:
(f, a1, ..., an),
which we normally read as:
f(a1, ..., an).
Thus, the first element of the sequence is an object used to transform the other elements to get an output value.
Here x[[1]]
is equivalent to:
(sin, a+b+1)
or, in more detail,
(sin, (+, a, (+, b, 1))).
Thus, x[[1]][2]
takes a subsequence of the above consisting of only the 2nd element and returns:
((+, a, (+, b, 1)))
(i.e. (a+b+1)()
- no args!). On the other hand x[[1]][[2]]
extracts (looks inside) the 2nd element and gives:
(+, a, (+, b, 1)),
i.e. a+b+1
(note one pair of parentheses less).
EDIT2: All of this exemplifies the beauty and expressiveness of the R language, at least IMHO. Let's study another example in which we create a call f1(f2(f3, f4), f3, f4)
,
which may be represented by a sequence
(f1, (f2, f3, f4), f3, f4).
We have:
f <- function(...) invisible(NULL)
f1 <- f; f2 <- f; f3 <- f; f4 <- f # for sake of clarity below
expr <- quote(f1(f2(f3, f4), f3, f4))
print(expr)
## f1(f2(f3, f4), f3, f4), i.e. (f1, (f2, f3, f4), f3, f4)
print(expr[1:3])
## f1(f2(f3, f4), f3), i.e. (f1, (f2, f3, f4), f3)
print(expr[3:4])
## f3(f4), i.e. (f3, f4)
print(expr[3])
## f3(), i.e. (f3)
expr[2]
## f2(f3, f4)(), i.e. ((f2, f3, f4)) [subsetting!]
And now for something completely different:
expr[[2]]
## f2(f3, f4), i.e. (f2, f3, f4) [extraction]
Hope this clarifies these issues a little bit.
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