Skip to content

Instantly share code, notes, and snippets.

@gmbecker
Created April 4, 2018 18:21
Show Gist options
  • Save gmbecker/c0e67645dd1e1a5262964a4728c79e61 to your computer and use it in GitHub Desktop.
Save gmbecker/c0e67645dd1e1a5262964a4728c79e61 to your computer and use it in GitHub Desktop.
Add argument specification to a function call
argify = function(expr, recursive = FALSE) {
if(is.character(expr))
expr = parse(text = expr)
else if(!is.call(expr))
expr = substitute(expr)
stopifnot(is.call(expr))
if(recursive && length(expr) > 1) {
for(i in 2:length(expr)) {
if(is.call(expr[[i]]))
expr[[i]] = argify(expr[[i]], TRUE)
}
}
fname = as.character(expr[[1]]) #name of function called
reffun = get(fname)
fun = function() { match.call()}
formals(fun) = formals(reffun)
assign(fname, fun)
eval(expr)
}
foo = function(arg1, arg2, arg3, arg4) NULL
bar = function(bar1, bar2) NULL
argify(foo(1, cbind(3, bar(3, 4)), "a", rnorm))
argify(foo(1, cbind(3, bar(3, 4)), "a", rnorm), recursive= TRUE)
@klmr
Copy link

klmr commented Apr 4, 2018

    reffun = get(fname)

This should use match.fun (or get(…, mode = 'function')); get alone can fail if the function is shadowed by a (non-function) variable.

… but isn’t the function needlessly complicated anyway? The last four lines of the function (L15–L18) can be replaced by a single

match.call(reffun, expr)

No need to inject the call into the original expression.

@gmbecker
Copy link
Author

gmbecker commented Apr 4, 2018

@klmr I think that's right. I had a bunch of balls in the air in terms of what I Was doing with the expression but given where it landed what you said is the better approach for that part.

@HenrikBengtsson you're right, thanks. The need for the [[1]] slipped my mind there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment