Getting runtime values of formal arguments in R - r

I have a function with default arguments which just returns its arguments as a list:
x <- function(a=1, b=2, c=3){formals()}
and another function which is a simple wrapper around x
y <- function(a, ...) x(a, ...)
However, in function x, I would like to get the runtime values of the arguments, not the default values. So that,
y(a=3, b=4)
should return
$a
[1] 3
$b
[1] 4
$c
[1] 3
and not
$a
[1] 1
$b
[1] 2
$c
[1] 3
which is what I get now. Maybe one of sys.* functions might help, but I am not so experienced on these... Is there an easy way to call a function like formals() to get the values of the arguments specified by the caller?

Maybe this?
x <- function(a=1, b=2, c=3) mget(names(formals()))
y <- function(a, ...) x(a, ...)
y(a=3, b=4)
#$a
#[1] 3
#
#$b
#[1] 4
#
#$c
#[1] 3

Related

How to pass functions as args in do.call?

I try to pass functions as args in do.call. For example:
testF <- function(a,b){
a(b)
}
ijk <- list(a = c(print, print), b = c(1,2))
do.call(testF, ijk, envir = .GlobalEnv)
#Error in a(b) : could not find function "a"
How to fix the above code?
Actually the right way. I think the issue lies in how you define your a in the list. Use function; also probably list is better than c.
ijk <- list(a=function(x) list(sqrt(x), x^2), b=c(4,9))
do.call(testF, ijk, envir=.GlobalEnv)
# [[1]]
# [1] 2 3
#
# [[2]]
# [1] 16 81

function to subset data supplying subset argument as text string

m <- matrix(1:4, ncol=2)
l <- list(a=1:3, b='c')
d <- data.frame(a=1:3, b=3:1)
I was wondering if it is possible to make a function that takes a base R object (matrix, vector, list or data.frame, ...) as well as a text that specifies the subset of the object.
f1 <- function(object, subset) {
# object'subset'
}
For instance
f1(m, '[1,1]') #to evaluate m[1,1]
f1(l, '[[1]][2:3]') #l[[1]][2:3]
f1(d, '$a') #d$a
would give us (respectively):
[1] 1
[1] 2 3
[1] 1 2 3
I guess the function need somehow to glue the two arguments before evaluating. I guess one could make a kind of interpreter for each bit of the subset text and the (for the matrix example) do something like:
`[`(1,1)
This would possible but I thought there would be an easier more direct way (my 'glue' above).
Well one way to go is to use eval(parse)) methodology, i.e.
f1 <- function(x, text){
eval(parse(text = paste0(x, text)))
}
f1('d', '$a')
#[1] 1 2 3
f1('m', '[1,1]')
#[1] 1
f1('l', '[[1]][2:3]')
#[1] 2 3
f1<-function(object, subset){
return(eval(parse(text=paste0(substitute(object),subset))))
}
> m=matrix(4,2,2)
> l=list(c(1,2,3),c(2,3,4))
> f1(m,'[1,1]')
[1] 4
> f1(l,'[[1]][1:2]')
[1] 1 2

How do I extract arguments in a function (written as a string) in R?

Let suppose I have defined a function by f <- function(x,y,z) {...}.
I would like to be able to transform an expression calling that function into a list of the parameters called by that function; it is the opposite of the do.call function.
For example, let us say I have such a function f, and I also have a string "f(2,1,3)".
How can I transform the string "f(2,1,3)" into the list of the parameters list(x=1,y=2,z=3)?
After you've parsed your character string into an R expression, use match.call() to match supplied to formal arguments.
f <- function(x,y,z) {}
x <- "f(1,2,3)"
ee <- parse(text = x)[[1]]
cc <- match.call(match.fun(ee[[1]]), ee)
as.list(cc)[-1]
# $x
# [1] 1
#
# $y
# [1] 2
#
# $z
# [1] 3
Alternatively:
f <- function(x,y,z) {...}
s <- "f(x = 2, y = 1, z = 3)"
c <- as.list(str2lang(s))
c[-1]
# $x
# [1] 2
#
# $y
# [1] 1
#
# $z
# [1] 3
I was looking for a solution to this a while ago in order to reconstruct a function call from a string. Hopefully this will be of use to someone who is looking for a solution to a similar problem.

apply a list of functions to a single argument in R

Hi I am trying to apply a list of functions to a single argument in R. For example,
flist <- list(F,G,H) #F,G,H are function objects
and say I want as a result a list or vector
(F(x),G(x),H(x)) where x is a scalar number.
Do you know how i can achieve that?
The most efficient way (it seems) to achieve this would be using a single lapply (instead of 3 different functions), such as
flist <- list(mean, unique, max) # Example functions list
MyScalar <- 1 # Some scalar
lapply(flist, function(f) f(MyScalar))
# [[1]]
# [1] 1
#
# [[2]]
# [1] 1
#
# [[3]]
# [1] 1
Though, if all the functions give the same size/class result, you could improve it even more using vapply
vapply(flist, function(x) x(MyScalar), FUN.VALUE = double(1))
## [1] 1 1 1
f <- function(x) x^1
g <- function(x) x^2
h <- function(x) x^3
l <- list(f, g, h)
sapply(l, do.call, list(2))
## [1] 2 4 8
do.call allows for function delegation with variable-length argument lists.
For example, c(1, 2, 3) can be called like so: do.call(c, list(1, 2, 3)).
(s|l)apply just iterates through a list and applies the specified function to each item. So the first iteration through l will be: do.call(l[[1]], list(2)), which is equivalent to l[[1]](2), which is equivalent to f(2).

Generalizable way for named ellipsis arguments sent to multiple functions [duplicate]

This question already has answers here:
Split up `...` arguments and distribute to multiple functions
(4 answers)
Closed 8 years ago.
I want to be able to take the ellipsis ... and use it in multiple child functions inside of a parent function. Doing so throws an error which is sensible as I am passing z to fun1 which has no z argument.
tester <- function(x, ...) {
list(a=x, b=fun1(...), c=fun2(...))
}
fun1 <- function(y) y * 6
fun2 <- function(z) z + 1
tester(z=4, y=5, x=6)
## > tester(z=4, y=5, x=6)
## Error in fun1(...) : unused argument (z = 4)
What is the most generalizable way to use arguments from an ellipsis in multiple child functions. Pretend the problem gets worse and we have 10000 child functions each getting different arguments from .... The desired output would be:
$a
[1] 6
$b
[1] 30
$c
[1] 5
I suspect it may be useful to capture the formals of each child function and match against the named arguments in ... but that seems less generalizable (but that may be as good as it gets).
If you can't change the input functions, you could try this:
tester <- function(x, ...) {
args <- as.list(match.call())[-1]
args1 <- head(names(as.list(args(fun1))), -1)
args2 <- head(names(as.list(args(fun2))), -1)
list(a=x, b=do.call(fun1, args[names(args) %in% args1]),
c=do.call(fun2, args[names(args) %in% args2]))
}
fun1 <- function(y) y * 6
fun2 <- function(z) z + 1
tester(z=4, y=5, x=6)
#$a
#[1] 6
#
#$b
#[1] 30
#
#$c
#[1] 5
It's awfully complicated and I wouldn't be surprised if you encounter dragons.
Here's #nicola's answer:
tester <- function(x, ...) {
list(a=x, b=fun1(...), c=fun2(...), d=path.expand2(...))
}
fun1 <- function(y, ...) y * 6
fun2 <- function(z, ...) z + 1
path.expand2 <- function(path, ...) path.expand(path)
tester(z=4, y=5, x=6, path="~/thepath")
## $a
## [1] 6
##
## $b
## [1] 30
##
## $c
## [1] 5
##
## $d
## [1] "C:/Users/trinker/thepath"

Resources