In R, when I do
substitute(function(a) { a })[[2]]
I see the following pairlist:
$a
Note that the value of the element is empty. How can I create such a pairlist? The following doesn't work for me :
> pairlist(a="")
$a
[1] ""
I am asking this in the context of programmatically creating a function. I want to do something like
> call("function", pairlist(a=""), call("{", as.symbol("a")))
function(a = "") {
a
}
This is quite close to what I get by doing
> substitute(function(a){a})
function(a) {
a
}
except for the function argument part.
try this:
> as.pairlist(alist(a=))
$a
maybe what you want to do is:
> f2 <- as.function(alist(a=1,b=,{a+b}))
> f2
function (a = 1, b)
{
a + b
}
With alist(a=).
You may also find the functions formals and body helpful in programatically creating a function, rather than substitute and call. Here's an example from the documentation ?formals
f <- function(x) a+b
formals(f) <- alist(a=,b=3) # function(a,b=3)a+b
f(2) # result = 5
which could be extended like this
body(f) <- expression(2*a+b)
f(2) # result = 7
Related
I have a function that looks like
my_function <- function(object)
{
# code goes here
}
I'd like the function (among other things) to print the name of the argument (as passed to the function). So if my function call is:
xxx <- my_function(my_object)
then I'd like to know how to get the function to print out the string "my_object".
Can anyone help please?
A more R-ish solution would be to use substitute (get substitute for obj) in combination with deparse (cast symbol to string):
my_function <- function(obj) {deparse(substitute(obj))}
General R metaprogramming rule: prefer substitute!
my_function(my_object)
## [1] "my_object"
I would suggest next approach which is closer to what you want. For sure you could modify it to obtain other outputs:
#Function
my_function <- function(x)
{
as.character(eval(parse(text=enquo(x)))[2])
}
#Apply
my_function(x = my_object)
Output:
[1] "my_object"
An improvement thanks to #MrFlick is next:
#Function
my_function <- function(x)
{
rlang::as_label(rlang::enquo(x))
}
#Apply
my_function(x = my_object)
Which produces same output with a more elegant style in the function:
[1] "my_object"
To display the entire call use match.call like this:
f <- function(x) { print(match.call()); x }
f(pi)
## f(x = pi)
## [1] 3.141593
IF it is desired to display the call just for debugging without modifying the function itself then use trace:
g <- function(x) x # test function
trace(g)
g(pi)
## trace: g(pi)
## [1] 3.141593
I want to write a function in R which grabs the name of a variable from the context of its caller's caller. I think the problem I have is best understood by asking how to compose deparse and substitute. You can see that a naive composition does not work:
# a compose operator
> `%c%` = function(x,y)function(...)x(y(...))
# a naive attempt to combine deparse and substitute
> desub = deparse %c% substitute
> f=function(foo) { message(desub(foo)) }
> f(log)
foo
# this is how it is supposed to work
> g=function(foo) { message(deparse(substitute(foo))) }
> g(log)
log
I also tried a couple of variations involving eval.parent but with no luck. Any help is appreciated.
Clarification: I'm not looking for a synonym for deparse(substitute(...)), e.g. match.call()[[2]] - what I'm looking for is a way to define a function
desub = function(foo) {
...
# What goes here?
}
such that the definition of f above produces the same answer as g. It should look like this:
> f=function(foo) { message(desub(foo)) }
> f(log)
log
Perhaps match.call could be of use in the body of desub above, but I'd like to know how. Thanks!
As you surmised, this is an issue with environments. The reason why the function f does not give log when you call f(log), is that the environment in which substitute is called, namely the evaluation environment of desub, does not contain a binding to log.
The remedy is to evaluate the call to substitute in the proper environment, and modify desub accordingly:
desub <- function(x, env = parent.frame()) {
deparse(eval(substitute(substitute(x)), envir = env))
}
Now f does what it was intended to do:
f(log)
#> log
Thanks to #egnha and #akrun for the brave attempts. After playing around a bit I found a solution that works.
This fragment:
desub <- function(y) {
e1=substitute(y)
e2=do.call(substitute,list(e1), env=parent.frame())
deparse(e2)
}
gives:
> f <- function(x) message(desub(x))
> f(log)
log
Update:
With help from Mark Bravington on the R-devel list, I was able to generalize this to multiple frames. I thought I should post it here, because it's a bit more useful than the above, and because there was a tricky workaround involving (possibly buggy?) behavior in parent.frame().
# desub(v,0)=="v"
# desub(v,1)==deparse(substitute(v))
# desub(v,2)==name of v in grandparent's frame
# etc.
desub = function(y,n=1) {
env=environment();
for(i in 0:n) {
y = do.call(substitute, list(substitute(y)), env=env)
env = do.call(my_mvb_parent, list(), env=env)
}
deparse(y)
}
# helper:
#
# - using mvb.parent.frame fixes problems with capture.output and
# weird cycling behavior in the built-in parent.frame
#
# - this wrapper makes mvb.parent.frame not throw an error when we get
# to globalenv()
my_mvb_parent=function() {
library(mvbutils)
tryCatch(
mvb.parent.frame(2),
error=function(e) { globalenv()})
}
if(1) {
# example code
g2=function(t) {
for(i in 0:5) {
res=desub(t,i);
print(res);
res1=capture.output(desub(t,i))
stopifnot(capture.output(res)==res1)
}
}
g1=function(z) g2(z)
g=function(y) g1(y)
g(log)
# prints:
## [1] "t"
## [1] "z"
## [1] "y"
## [1] "log"
## [1] "log"
## [1] "log"
}
I'm learning R programming. I'm unable to understand how function within function works in R. Example:
f <- function(y) {
function() { y }
}
f()
f(2)()
I'm not able to understand why $f() is not working and showing following message:
function() { y }
<environment: 0x0000000015e8d470>
but when I use $f(4)() then it is showing answer as 4.
Please explain your answer in brief so that I can understand it easily.
For a more general case, let's change the "inner" function a little bit:
f <- function(y) {
function(x) { y + x}
}
Now f(2) returns a function that adds 2 to its argument. The value 2 is kept in the function's environment:
> f(2)
function(x) { y + x}
<environment: 0x0000000015a690f0>
> environment(f(2))$y
[1] 2
.. and you can change it if you really want to but for this you need to assign a name to the output of f():
> g <- f(2)
> environment(g)$y
[1] 2
> environment(g)$y <- 3
> g(1)
[1] 4
Why do you need a g here? Because otherwise, the environment created with f(2) is garbage collected immediately, so there's no way to access it:
> environment(f(2))$y<-4
Error in environment(f(2))$y <- 4 :
target of assignment expands to non-language object
This won't affect the case when you use, say, f(2) only once:
> f(2)(3)
[1] 5
The reason is that the inner function behave as the answer of the outer one son by just doing f(), the result is a function. The best way is to call it double f(3)() as the inner function doesn't take any argument.
Lets say I have a function that accepts variables that are always part of a list.
myfun <- function(x$name,y$name) {
# stuff
}
What I'd like to do is get the names used.
alist <- list(Hello=1,Goodbye=2)
myfun(alist$Hello, alist$Goodbye) {
# I want to be able to work with the characters "Hello" and "Goodby" in here
}
So, within my function, how would I get the characters "Hello" and "Goodbye". Given alist$Hello and alist$Goodbye
I recall that plot.default does this with deparse(substitute(:
a <- list(a="hello",b=c(1,2,3))
f <- function(x,y) { print(deparse(substitute(x))); print(deparse(substitute(y))) }
f(a$a,a$b)
#[1] "a$a"
#[1] "a$b"
Something like this, perhaps:
myfun <- function(x) { print(substitute(x))}
myfun(iris$Sepal.Length)
## iris$Sepal.Length
I'd create the function with a list argument:
myfun <- function(l) {
print(names(alist))
}
myfun(alist)
# [1] "Hello" "Goodbye"
this may seem like a overly complicated question, but it has me driving me a little nuts for some time. It is also for curiosity, because I already have a way of doing what I need, so is not that important.
In R, I need a function to return a named list object with all the arguments and the values entered by the user. For this I have made this code (toy example):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- frm
for (i in 1:length(frm))
parms[[i]] <- get(names(frm)[i])
return(parms)
}
So when this is asked:
> foo(b=0)
$a
[1] 1
$b
[1] 0
$h
[1] "coconut"
This result is perfect. The thing is, when I try to use lapply to the same goal, so as to be a little more efficient (and elegant), it does not work as I want it to:
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get)
names(parms) <- names(frm)
return(parms)
}
The problem clearly is with the environment in which get evaluates it's first argument (a character string, the name of the variable). This I know in part from the error message:
> foo(b=0)
Error in FUN(c("a", "b", "h")[[1L]], ...) : object 'a' not found
and also, because when in the .GlobalEnv environment there are objects with the right names, foo returns their values instead:
> a <- 100
> b <- -1
> h <- 'wallnut'
> foo(b=0)
$a
[1] 100
$b
[1] -1
$h
[1] "wallnut"
Obviously, as get by default evaluates in the parent.frame(), it searches for the objects in the .GlobalEnv environment, instead of that of the current function. This is strange, since this does not happen with the first version of the function.
I have tried many options to make the function get to evaluate in the right environment, but could not do it correctly (I've tried pos=-2,0,1,2 and envir=NULL as options).
If anyone happen to know a little more than me about environments, specially in this "strange" cases, I would love to know how to solve this.
Thanks for your time,
Juan
Edit of 2013-08-05
Using sapply() instead of lapply(), simplifies this considerably:
foo4 <- function(a=1, b=5, h='coconut') {
frm <- formals(sys.function())
sapply(names(frm), get, envir=sys.frame(sys.parent(0)), simplify=FALSE)
}
foo4(b=0, h='mango')
This, though, without sapply() or lapply() might be the more elegant solution:
foo5 <- function(a=1, b=5, h='coconut') {
modifyList(formals(sys.function()), as.list(match.call())[-1])
}
foo5(b=0, h='mango')
Original post (2011-11-04)
After casting about a bit, this looks to be the best solution.
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- lapply(names(frm), get, envir=sys.frame(sys.parent(0)))
names(parms) <- names(frm)
return(parms)
}
foo(b=0, h='mango')
# $a
# [1] 1
# $b
# [1] 0
# $h
# [1] "mango"
There's some subtle stuff going on here with the way that lapply scopes/evaluates the calls that it constructs. The details are hidden in a call to .Internal(lapply(X, FUN)), but for a taste, compare these two calls:
# With function matched by match.fun, search in sys.parent(0)
foo2 <- function(a=1, h='coconut') {
lapply(names(formals()),
get, envir = sys.parent(0))
}
# With anonymous function, search in sys.parent(2)
foo3 <- function(a=1, h='coconut') {
lapply(names(formals()),
FUN = function(X) get(X, envir = sys.parent(2)))
}
foo4(a=0, h='mango')
foo5(a=0, h='mango')
Just convert the current environment into a list:
foo <- function(a=1, b=5, h='coconut') {
as.list(environment())
}
foo(a = 0, h = 'mango')
This is adapted from #Josh O'Brien's solution above using sapply to automatically assign the correct names to the resulting list (saves one line of code):
foo <- function(a=1, b=5, h='coconut') {
frm <- formals(foo)
parms <- sapply(names(frm), get, envir=sys.frame(sys.parent(-1)), simplify=FALSE)
return(parms)
}