Skip to content

Instantly share code, notes, and snippets.

@dmi3kno
Last active June 13, 2020 17:02
Show Gist options
  • Save dmi3kno/67d72288327cd10a001997282cfe0e02 to your computer and use it in GitHub Desktop.
Save dmi3kno/67d72288327cd10a001997282cfe0e02 to your computer and use it in GitHub Desktop.
Example of formals-aware decorator
is.unset<-function(x)
x==as.list(alist(a=))[[1]]
is.nameempty <- function(x){
nx <- names(x)
if(is.null(nx))
return(rep(TRUE, length(x)))
is.na(nx) | nx==""
}
match_to_formals <- function(a, f, keep_passed_names=TRUE){
l_wo_names <- is.nameempty(a)
# named arguments only
a_w_names <- names(a)[!l_wo_names]
# how many arguments are unnamed
l_unn <- length(a[l_wo_names])
# formals, which have not been explicitly referred to in arguments
nms_f <- names(f)[!names(f) %in% a_w_names]
# position of dots in unreferred formals, if not found, assumed to be at the end
dots_pos <- match("...", nms_f, nomatch = length(nms_f)+1)
# foreign names (names passed to dots) can be suppressed, but it is probably not a good idea
if(!keep_passed_names){
a_w_names <- ifelse(a_w_names %in% names(f), a_w_names, "...")
names(a)[!l_wo_names] <- a_w_names # this part has names so it is matched literally
}
names(a)[l_wo_names] <- c(nms_f[seq_len(min(l_unn, dots_pos-1))], # this part is matched by position
rep.int("...", times=max(0,l_unn-dots_pos+1))) # this part is passed to dots
a
}
myfun <- function(a,..., b=1, NArm=TRUE){
(a-b*sum(..., na.rm=NArm))
}
consciously <- function(fun, x){
f_formals <- formals(args(fun))
function(...){
arg_lst <- list(...)
af <- match_to_formals(arg_lst, f_formals)
message("Here's what I got:")
message(str(af))
fun(...)
#do.call(fun, af) # if you want to modify arguments
}
}
conscious_myfun <- consciously(myfun)
conscious_myfun(1:3, 1:3, k=5:7, b=0.4)
#> Here's what I got:
#> List of 4
#> $ a : int [1:3] 1 2 3
#> $ ...: int [1:3] 1 2 3
#> $ k : int [1:3] 5 6 7
#> $ b : num 0.4
#>
#> [1] -8.6 -7.6 -6.6
#<sup>Created on 2020-06-08 by the [reprex package](https://reprex.tidyverse.org) (v0.3.0)</sup>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment