Strange substitute() behavior inside lapply() - r

Could someone explain the following result :
R> lapply(1:2, function(v) substitute(v))
[[1]]
1:2[[2L]]
[[2]]
1:2[[2L]]
Given the definition of lapply, I thought that this should have returned a list with elements substitute(1) and substitute(2). It is as if substitute(v) was not evaluated in the anonymous function scope, but in the "parent" one.
What I find even more strange is that if I add eval to substitute, I get the result I was waiting for :
R> lapply(1:2, function(v) eval(substitute(v)))
[[1]]
[1] 1
[[2]]
[1] 2
I know these questions are a bit tricky, but there is clearly something I don't get here.

Related

Accessing the function that is being called from within the function

Within a function, how can we reliably return an object that contains the function itself?
For example with:
functionBuilder <- function(wordToSay) {
function(otherWordToSay) {
print(wordToSay)
print(otherWordToSay)
get(as.character(match.call()[[1]]))
}
}
I can build a function like so:
functionToRun <- functionBuilder("hello nested world")
... and run it ...
functionToRun("A")
#[1] "hello nested world"
#[1] "A"
#
#function(otherWordToSay) {
# print(wordToSay)
# print(otherWordToSay)
# get(as.character(match.call()[[1]]))
# }
#<environment: 0x1e313678>
... as you can see functionToRun returns itself. However, this approach appears to break if I call functionToRun via sapply:
> sapply(LETTERS, functionToRun)
#[1] "hello nested world"
#[1] "A"
#Error in get(as.character(match.call()[[1]])) : object 'FUN' not found
I can see that this is because the actual call when using sapply is FUN but that FUN doesn't exist at pos = -1 (the default for get). Code that works in that position looks like:
get(as.character(match.call()[[1]]),envir = sys.frame(sys.parent()))
But that same code fails if the function hasn't been called via sapply because sys.frame(sys.parent())) goes too far back and ends up referring to R_GlobalEnv.
From the documentation (R 3.2.2) I'd have expected dynGet to perhaps solve the issue of only going as far back in the stack as needed. Although this works for an sapply call of the function, it fails when the function is called on its own. (Besides, it is marked as 'somewhat experimental'). Inversely getAnywhere seems promising, but doesn't seem to work for the sapply called function.
Is there a reliable way to return the function that is currently being processed, i.e. works for both a bare and sapply wrapped function call?
What I'm doing right now is wrapping the attempt to grab the function in a tryCatch; but I'm a little uncertain whether I can trust that get(as.character(match.call()[[1]]),envir = sys.frame(sys.parent())) will work in all wrapping cases (not just sapply). So, I'm looking for a more reasonable way to approach this problem.
Potentially Related Questions:
How to access a variable stored in a function in R
How to get the name of the calling function inside the called routine?
I can't guarantee that this will work in all cases, but it looks okay:
fun <- function(x) {
print(x)
y <- exp(x)
print(y)
sys.function(0)
}
fun(1)
# [1] 1
# [1] 2.718282
# function(x) {
# print(x)
# y <- exp(x)
# print(y)
# sys.function(0)
# }
lapply(1:5, fun)[[3]]
# [1] 1
# [1] 2.718282
# [1] 2
# [1] 7.389056
# [1] 3
# [1] 20.08554
# [1] 4
# [1] 54.59815
# [1] 5
# [1] 148.4132
# function(x) {
# print(x)
# y <- exp(x)
# print(y)
# sys.function(0)
# }
Of course, I don't understand what you need this for.

How can I turn a list of expressions to an expression list

Suppose a function like this:
fun <- function(...) {
dots <- eval(substitute(alist(...)))
# ...
}
... is supposed to be a few expressions that should be evaluated in some other environments in the function. For example, fun(name,age) will result in a ACTUAL list of name objects like:
[[1]]
name
[[2]]
age
However, I want to evaluate an expression (in some environment) like this: list(name,age) which is an EXPRESSION rather than ACTUAL list that include the user-defined arguments.
How can I make that transformation?
I'm not totally clear what you want evaluated where, but if you replace alist with list:
fun <- function(..., e) {
dots <- eval(substitute(list(...)),envir=e)
dots
}
and set:
e=new.env() ; e$name="Fred"; e$age=99
and then:
fun(name,age,age*2,e=e)
[[1]]
[1] "Fred"
[[2]]
[1] 99
[[3]]
[1] 198
which seems to qualify as "evaluate an expression (in some environment) like this: list(name,age)", since, at top level, evaluating list(name,age) is simply this, right:
> name="Joe"
> age=123
> list(name,age)
[[1]]
[1] "Joe"
[[2]]
[1] 123
As always, it is somewhat unclear exactly what you want, But I think
fun <- function(...) {
dots <- eval(substitute(alist(...)))
as.call(c(list(quote(list)),dots))
}
get's the result you want. Here we take the expressions passed in via dots, and use them as parameters to a call to the list() function. This means that
ex <- fun(name, age, gender)
ex
# list(name, age)
class(ex)
# [1] "call"
And really, an expression is just a collection of calls so I'd assume a call would work for you, but if you really wanted an expression, you could use as.expression(ex).

R get objects' names from the list of objects

I try to get an object's name from the list containing this object. I searched through similar questions and find some suggestions about using the deparse(substitute(object)) formula:
> my.list <- list(model.product, model.i, model.add)
> lapply(my.list, function(model) deparse(substitute(model)))
and the result is:
[[1]]
[1] "X[[1L]]"
[[2]]
[1] "X[[2L]]"
[[3]]
[1] "X[[3L]]"
whereas I want to obtain:
[1] "model.product", "model.i", "model.add"
Thank you in advance for being of some help!
You can write your own list() function so it behaves like data.frame(), i.e., uses the un-evaluated arg names as entry names:
List <- function(...) {
names <- as.list(substitute(list(...)))[-1L]
setNames(list(...), names)
}
my.list <- List(model.product, model.i, model.add)
Then you can just access the names via:
names(my.list)
names(my.list) #..............
Oh wait, you didn't actually create names did you? There is actually no "memory" for the list function. It returns a list with the values of its arguments but not from whence they came, unless you add names to the pairlist given as the argument.
You won't be able to extract the information that way once you've created my.list.
The underlying way R works is that expressions are not evaluated until they're needed; using deparse(substitute()) will only work before the expression has been evaluated. So:
deparse(substitute(list(model.product, model.i, model.add)))
should work, while yours doesn't.
To save stuffing around, you could employ mget to collect your free-floating variables into a list with the names included:
one <- two <- three <- 1
result <- mget(c("one","two","three"))
result
#$one
#[1] 1
#
#$two
#[1] 1
#
#$three
#[1] 1
Then you can follow #DWin's suggestion:
names(result)
#[1] "one" "two" "three"

Ambiguous variation of default environment in `getClasses()` (standard function vs. formal S4 method)

I'm having some trouble figuring out what's exactly going on here with respect to "environment nesting"/lexical scoping:
The problem
The default value of argument where in function getClasses() seems to vary depending on whether getClasses() is called inside a standard R function or a formal S4 method. It is controlled by .externalCallerEnv() which seems to be "object" to lazy evaluation and thus causes the variation (see EDIT below)
The question
When called from inside a formal S4 method, how do I set where to the same value that is the default value when getClasses() is called inside a standard function?
ILLUSTRATION
Below you'll find a short illustration of the "problematic behavior" described above
1) Custom classes
I've got numerous class defs that are currently sourced to .GlobalEnv.
Let's take this one as a representative for all of them
setRefClass("A", fields=list(x="numeric"))
2) Listing available classes
Via argument where, function getClasses lets me choose the environment in which to look for classes.
The following seems to look everywhere except .GlobalEnv and thus doesn't find my class; that's fine:
classes <- getClasses()
> head(classes)
[1] "(" ".environment" ".externalptr" ".name" ".NULL"
[6] ".Other"
> "A" %in% classes
[1] FALSE
Now I look in .GlobalEnv and find class A only; that's fine too:
classes <- getClasses(where=.GlobalEnv)
> classes
[1] "A"
> "A" %in% classes
[1] TRUE
3) Creating a custom standard lookup function
When I put the lookup via getClasses into a standard function (this is just the first part of a desired functionality and I'd like to compute getClasses() inside that method rather than passing it's return value as an formal argument), everything still works fine
foo1 <- function(where=.GlobalEnv) {
if (is.null(where)) {
x <- getClasses()
} else {
x <- getClasses(where=where)
}
return(x)
}
> foo1()
[1] "A"
> classes <- foo1(where=NULL)
> head(classes)
[1] "(" ".environment" ".externalptr" ".name" ".NULL"
[6] ".Other"
> "A" %in% classes
[1] FALSE
4) Creating a formal S4 method
However, once I put everything into a formal S4 method, there seems to be some changes with respect to the standard environment that getClasses() uses to look for classes
setGeneric(
name="foo2",
signature="x",
def=function(x, ...) standardGeneric("foo2")
)
setMethod(
f="foo2",
signature=signature(x="missing"),
definition=function(
x,
where=.GlobalEnv
) {
if (is.null(where)) {
x <- getClasses()
} else {
x <- getClasses(where=where)
}
return(x)
}
)
[1] "foo2"
> foo2()
[1] "A"
> classes <- foo2(where=NULL)
> head(classes)
[1] "A" "(" ".environment" ".externalptr" ".name"
[6] ".NULL"
> "A" %in% classes
[1] TRUE
Before, "A" %in% foo1(where=NULL) was FALSE (desired) whereas "A" %in% foo2(where=NULL) is TRUE now (not desired).
Any ideas how foo2() would behave the exact same way as foo1()?
EDIT 2012-08-29
As Josh O'Brien pointed out in his comment below, the variation is probably caused by lazy evaluation.
Debugging foo1()
debug(getClasses)
foo1(where=NULL)
You enter the debugging tracer; hit <RETURN> 4 times followed by typing get("where"):
Browse[2]> get("where")
<environment: namespace:base>
In the console, hit <RETURN> 1 time followed by typing evList:
Browse[2]> evList
[[1]]
<environment: namespace:base>
Type Q to quit the current debugging run
Now run everything again, but with slightly different debugging calls
foo1(where=NULL)
In the console, hit <RETURN> 5 times followed by typing evList:
Browse[2]> evList
[[1]]
<environment: namespace:methods>
Now type get("where"):
Browse[2]> get("where")
<environment: namespace:methods>
Now where points to namespace:methods
Debugging `foo2()'
foo2(where=NULL)
You enter the debugging tracer; hit <RETURN> 4 times followed by typing get("where"):
Browse[2]> get("where")
<environment: namespace:base>
Then hit <RETURN> 1 time followed by typing evList:
Browse[2]> evList
[[1]]
<environment: namespace:base>
Type Q to quit the current debugging run
Now run everything again, but with slightly different debugging calls
foo2(where=NULL)
Hit <RETURN> 5 times followed by typing evList:
Browse[2]> evList
[[1]]
<environment: 0x02a68db8>
[[2]]
<environment: R_GlobalEnv>
# [OMITTED]
[[8]]
<environment: package:methods>
attr(,"name")
[1] "package:methods"
attr(,"path")
[1] "R:/Apps/LSQMApps/apps/R/R-2.14.1/library/methods"
[[9]]
<environment: 0x01e8501c>
attr(,"name")
[1] "Autoloads"
[[10]]
<environment: namespace:base>
Now type get("where"):
Browse[2]> get("where")
<environment: 0x02a68db8>
and note the different values of evList and where compared to the debugging run before. Type Q to quit the current debugging run.
This seems somewhat strange to me, but probably makes sense from the language designers' perspective. I'd probably be fine once I know how to explicitly set where to point to the environment associated with the namespace:methods.
A well known lesson learned yet again: it's always good to be explicit ;-)
Thanks to Josh O'Brien and this post by Etiennebr I guess I'm able to put the pieces together.
Due to lazy evaluation and lexical scoping, I think the only way to really make sure getClasses() behaves the same way as if called from either .GlobalEnv or from inside a regular function is to explicitly set the value of where to the environment associated to namespace:methods when calling getClasses() inside a formal S4 method.
To get the environment associated to the namespace, this seems to work:
env <- loadNamespace("methods")
> is.environment(env)
[1] TRUE
Alternatively or even better:
env <- asNamespace("methods")
> is.environment(env)
[1] TRUE
This environment is exactly the one we need to point where to
setGeneric(
name="foo2",
signature="x",
def=function(x, ...) standardGeneric("foo2")
)
setMethod(
f="foo2",
signature=signature(x="missing"),
definition=function(
x,
where=.GlobalEnv
) {
if (is.null(where)) {
x <- getClasses(where=asNamespace("methods"))
} else {
x <- getClasses(where=where)
}
return(x)
}
)
> foo2()
[1] "A"
> classes <- foo2(where=NULL)
> head(classes)
[1] "(" ".environment" ".externalptr" ".name" ".NULL"
[6] ".Other"
> "A" %in% classes
[1] FALSE

R - Get formals from call object

How can I get the formals (arguments) from a call object? formals() only seems to work with functions.
Well, a call does not have formals, only actual arguments... The difference being that a function like foo <- function(x, y, ..., z=42) can be called with actual arguments like foo(42, bar=13).
...But getting the arguments can be done like this:
a <- call('foo', a=42, 13)
as.list(a)[-1]
#$a
#[1] 42
#
#[[2]]
#[1] 13
...on the other hand, you can usually (not always) find the actual function and find the formals for it:
a <- quote(which(letters=='g'))
formals(match.fun(a[[1]]))
#$x
#
#$arr.ind
#[1] FALSE
#
#$useNames
#[1] TRUE
Here you'd need to add some error handling if the function can't be found (as with the call to foo above)...

Resources