For an arbitrary function
f <- function(x, y = 3){
z <- x + y
z^2
}
I want to be able take the argument names of f
> argument_names(f)
[1] "x" "y"
Is this possible?
formalArgs and formals are two functions that would be useful in this case. If you just want the parameter names then formalArgs will be more useful as it just gives the names and ignores any defaults. formals gives a list as the output and provides the parameter name as the name of the element in the list and the default as the value of the element.
f <- function(x, y = 3){
z <- x + y
z^2
}
> formalArgs(f)
[1] "x" "y"
> formals(f)
$x
$y
[1] 3
My first inclination was to just suggest formals and if you just wanted the names of the parameters you could use names like names(formals(f)). The formalArgs function just is a wrapper that does that for you so either way works.
Edit: Note that technically primitive functions don't have "formals" so this method will return NULL if used on primitives. A way around that is to first wrap the function in args before passing to formalArgs. This works regardless of it the function is primitive or not.
> # formalArgs will work for non-primitives but not primitives
> formalArgs(f)
[1] "x" "y"
> formalArgs(sum)
NULL
> # But wrapping the function in args first will work in either case
> formalArgs(args(f))
[1] "x" "y"
> formalArgs(args(sum))
[1] "..." "na.rm"
Related
I am looking for the reverse of get().
Given an object name, I wish to have the character string representing that object extracted directly from the object.
Trivial example with foo being the placeholder for the function I am looking for.
z <- data.frame(x=1:10, y=1:10)
test <- function(a){
mean.x <- mean(a$x)
print(foo(a))
return(mean.x)}
test(z)
Would print:
"z"
My work around, which is harder to implement in my current problem is:
test <- function(a="z"){
mean.x <- mean(get(a)$x)
print(a)
return(mean.x)}
test("z")
The old deparse-substitute trick:
a<-data.frame(x=1:10,y=1:10)
test<-function(z){
mean.x<-mean(z$x)
nm <-deparse(substitute(z))
print(nm)
return(mean.x)}
test(a)
#[1] "a" ... this is the side-effect of the print() call
# ... you could have done something useful with that character value
#[1] 5.5 ... this is the result of the function call
Edit: Ran it with the new test-object
Note: this will not succeed inside a local function when a set of list items are passed from the first argument to lapply (and it also fails when an object is passed from a list given to a for-loop.) You would be able to extract the ".Names"-attribute and the order of processing from the structure result, if it were a named vector that were being processed.
> lapply( list(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a # This "a" and the next one in the print output are put in after processing
$a[[1]]
[1] "X" "" "1L]]" # Notice that there was no "a"
$b
$b[[1]]
[1] "X" "" "2L]]"
> lapply( c(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a
$a[[1]] # but it's theoretically possible to extract when its an atomic vector
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "1L]]"
$b
$b[[1]]
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "2L]]"
deparse(quote(var))
My intuitive understanding
In which the quote freeze the var or expression from evaluation
and the deparse function which is the inverse of parse function makes that freezed symbol back to String
Note that for print methods the behavior can be different.
print.foo=function(x){ print(deparse(substitute(x))) }
test = list(a=1, b=2)
class(test)="foo"
#this shows "test" as expected
print(test)
#this (just typing 'test' on the R command line)
test
#shows
#"structure(list(a = 1, b = 2), .Names = c(\"a\", \"b\"), class = \"foo\")"
Other comments I've seen on forums suggests that the last behavior is unavoidable. This is unfortunate if you are writing print methods for packages.
To elaborate on Eli Holmes' answer:
myfunc works beautifully
I was tempted to call it within another function (as discussed in his Aug 15, '20 comment)
Fail
Within a function, coded directly (rather than called from an external function), the deparse(substitute() trick works well.
This is all implicit in his answer, but for the benefit of peeps with my degree of obliviousness, I wanted to spell it out.
an_object <- mtcars
myfunc <- function(x) deparse(substitute(x))
myfunc(an_object)
#> [1] "an_object"
# called within another function
wrapper <- function(x){
myfunc(x)
}
wrapper(an_object)
#> [1] "x"
I am looking for the reverse of get().
Given an object name, I wish to have the character string representing that object extracted directly from the object.
Trivial example with foo being the placeholder for the function I am looking for.
z <- data.frame(x=1:10, y=1:10)
test <- function(a){
mean.x <- mean(a$x)
print(foo(a))
return(mean.x)}
test(z)
Would print:
"z"
My work around, which is harder to implement in my current problem is:
test <- function(a="z"){
mean.x <- mean(get(a)$x)
print(a)
return(mean.x)}
test("z")
The old deparse-substitute trick:
a<-data.frame(x=1:10,y=1:10)
test<-function(z){
mean.x<-mean(z$x)
nm <-deparse(substitute(z))
print(nm)
return(mean.x)}
test(a)
#[1] "a" ... this is the side-effect of the print() call
# ... you could have done something useful with that character value
#[1] 5.5 ... this is the result of the function call
Edit: Ran it with the new test-object
Note: this will not succeed inside a local function when a set of list items are passed from the first argument to lapply (and it also fails when an object is passed from a list given to a for-loop.) You would be able to extract the ".Names"-attribute and the order of processing from the structure result, if it were a named vector that were being processed.
> lapply( list(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a # This "a" and the next one in the print output are put in after processing
$a[[1]]
[1] "X" "" "1L]]" # Notice that there was no "a"
$b
$b[[1]]
[1] "X" "" "2L]]"
> lapply( c(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a
$a[[1]] # but it's theoretically possible to extract when its an atomic vector
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "1L]]"
$b
$b[[1]]
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "2L]]"
deparse(quote(var))
My intuitive understanding
In which the quote freeze the var or expression from evaluation
and the deparse function which is the inverse of parse function makes that freezed symbol back to String
Note that for print methods the behavior can be different.
print.foo=function(x){ print(deparse(substitute(x))) }
test = list(a=1, b=2)
class(test)="foo"
#this shows "test" as expected
print(test)
#this (just typing 'test' on the R command line)
test
#shows
#"structure(list(a = 1, b = 2), .Names = c(\"a\", \"b\"), class = \"foo\")"
Other comments I've seen on forums suggests that the last behavior is unavoidable. This is unfortunate if you are writing print methods for packages.
To elaborate on Eli Holmes' answer:
myfunc works beautifully
I was tempted to call it within another function (as discussed in his Aug 15, '20 comment)
Fail
Within a function, coded directly (rather than called from an external function), the deparse(substitute() trick works well.
This is all implicit in his answer, but for the benefit of peeps with my degree of obliviousness, I wanted to spell it out.
an_object <- mtcars
myfunc <- function(x) deparse(substitute(x))
myfunc(an_object)
#> [1] "an_object"
# called within another function
wrapper <- function(x){
myfunc(x)
}
wrapper(an_object)
#> [1] "x"
I am looking for the reverse of get().
Given an object name, I wish to have the character string representing that object extracted directly from the object.
Trivial example with foo being the placeholder for the function I am looking for.
z <- data.frame(x=1:10, y=1:10)
test <- function(a){
mean.x <- mean(a$x)
print(foo(a))
return(mean.x)}
test(z)
Would print:
"z"
My work around, which is harder to implement in my current problem is:
test <- function(a="z"){
mean.x <- mean(get(a)$x)
print(a)
return(mean.x)}
test("z")
The old deparse-substitute trick:
a<-data.frame(x=1:10,y=1:10)
test<-function(z){
mean.x<-mean(z$x)
nm <-deparse(substitute(z))
print(nm)
return(mean.x)}
test(a)
#[1] "a" ... this is the side-effect of the print() call
# ... you could have done something useful with that character value
#[1] 5.5 ... this is the result of the function call
Edit: Ran it with the new test-object
Note: this will not succeed inside a local function when a set of list items are passed from the first argument to lapply (and it also fails when an object is passed from a list given to a for-loop.) You would be able to extract the ".Names"-attribute and the order of processing from the structure result, if it were a named vector that were being processed.
> lapply( list(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a # This "a" and the next one in the print output are put in after processing
$a[[1]]
[1] "X" "" "1L]]" # Notice that there was no "a"
$b
$b[[1]]
[1] "X" "" "2L]]"
> lapply( c(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a
$a[[1]] # but it's theoretically possible to extract when its an atomic vector
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "1L]]"
$b
$b[[1]]
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "2L]]"
deparse(quote(var))
My intuitive understanding
In which the quote freeze the var or expression from evaluation
and the deparse function which is the inverse of parse function makes that freezed symbol back to String
Note that for print methods the behavior can be different.
print.foo=function(x){ print(deparse(substitute(x))) }
test = list(a=1, b=2)
class(test)="foo"
#this shows "test" as expected
print(test)
#this (just typing 'test' on the R command line)
test
#shows
#"structure(list(a = 1, b = 2), .Names = c(\"a\", \"b\"), class = \"foo\")"
Other comments I've seen on forums suggests that the last behavior is unavoidable. This is unfortunate if you are writing print methods for packages.
To elaborate on Eli Holmes' answer:
myfunc works beautifully
I was tempted to call it within another function (as discussed in his Aug 15, '20 comment)
Fail
Within a function, coded directly (rather than called from an external function), the deparse(substitute() trick works well.
This is all implicit in his answer, but for the benefit of peeps with my degree of obliviousness, I wanted to spell it out.
an_object <- mtcars
myfunc <- function(x) deparse(substitute(x))
myfunc(an_object)
#> [1] "an_object"
# called within another function
wrapper <- function(x){
myfunc(x)
}
wrapper(an_object)
#> [1] "x"
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).
The title is the self-contained question. An example clarifies it: Consider
x=list(a=1, b="name")
f <- function(){
assign('y[["d"]]', FALSE, parent.frame() )
}
g <- function(y) {f(); print(y)}
g(x)
$a
[1] 1
$b
[1] "name"
whereas I would like to get
g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
A few remarks. I knew what is wrong in my original example, but am using it to make clear my objective. I want to avoid <<-, and want x to be changed in the parent frame.
I think my understanding of environments is primitive, and any references are appreciated.
The first argument to assign must be a variable name, not the character representation of an expression. Try replacing f with:
f <- function() with(parent.frame(), y$d <- FALSE)
Note that a, b and d are list components, not list attributes. If we wanted to add an attribute "d" to y in f's parent frame we would do this:
f <- function() with(parent.frame(), attr(y, "d") <- FALSE)
Also, note that depending on what you want to do it may (or may not) be better to have x be an environment or a proto object (from the proto package).
assign's first argument needs to be an object name. Your use of assign is basically the same as the counter-example at the end of the the assign help page. Observe:
> x=list(a=1, b="name")
> f <- function(){
+ assign('x["d"]', FALSE, parent.frame() )
+ }
> g <- function(y) {f(); print(`x["d"]`)}
> g(x)
[1] FALSE # a variable with the name `x["d"]` was created
This may be where you want to use "<<-" but it's generally considered suspect.
> f <- function(){
+ x$d <<- FALSE
+ }
> g <- function(y) {f(); print(y)}
> g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
A further thought, offered in the absence of any goal for this exercise and ignoring the term "attributes" which Gabor has pointed out has a specific meaning in R, but may not have been your goal. If all you want is the output to match your specs then this achieves that goal but take notice that no alteration of x in the global environment is occurring.
> f <- function(){
+ assign('y', c(x, d=FALSE), parent.frame() )
+ }
> g <- function(y) {f(); print(y)}
> g(x)
$a
[1] 1
$b
[1] "name"
$d
[1] FALSE
> x # `x` is unchanged
$a
[1] 1
$b
[1] "name"
The parent.frame for f is what might be called the "interior of g but the alteration does not propagate out to the global environment.