Last active
June 13, 2020 17:02
-
-
Save dmi3kno/67d72288327cd10a001997282cfe0e02 to your computer and use it in GitHub Desktop.
Example of formals-aware decorator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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