I have the need for a function generator that takes another function and any arguments of that function and sets new defaults. I thought @hadley's pryr::partial
was that magic function. It does exactly what I want except you can't then change that new default. So here I can change sep
in my new paste
function but not the new default of collapse = "_BAR_"
. How can I make partial
perform this way (i.e., default to collapse = "_BAR_"
but enable setting it to collapse = NULL
if desired)? If this is not possible with partial
is there a way to rewrite the code for partial
to do this: https://github.com/hadley/pryr/blob/master/R/partial.r
library(pryr)
.paste <- pryr::partial(paste, collapse = "_FOO_")
.paste(1:5)
.paste(1:5, LETTERS[1:5], sep="_BAR_")
.paste(1:5, collapse=NULL)
> .paste(1:5)
[1] "1_FOO_2_FOO_3_FOO_4_FOO_5"
> .paste(1:5, LETTERS[1:5], sep="_BAR_")
[1] "1_BAR_A_FOO_2_BAR_B_FOO_3_BAR_C_FOO_4_BAR_D_FOO_5_BAR_E"
> .paste(1:5, collapse=NULL)
Error in paste(collapse = "_FOO_", ...) :
formal argument "collapse" matched by multiple actual arguments
partial
is good for fixing certain parameter values, but if you want to change defaults, you might consider a different strategy. This would work
.paste <- paste
formals(.paste)$collapse <- "_FOO_"
This changes the parameters to the function
args(.paste)
# function (..., sep = " ", collapse = "_FOO_")
# NULL
Then you can do
.paste(1:5)
# [1] "1_FOO_2_FOO_3_FOO_4_FOO_5"
.paste(1:5, LETTERS[1:5], sep="_BAR_")
# [1] "1_BAR_A_FOO_2_BAR_B_FOO_3_BAR_C_FOO_4_BAR_D_FOO_5_BAR_E"
.paste(1:5, collapse=NULL)
# [1] "1" "2" "3" "4" "5"
This is a canned function taking @MrFlick's great response and putting it into a function for future searchers:
hijack <- function(FUN, ...){
.FUN <- FUN
args <- list(...)
invisible(lapply(seq_along(args), function(i) {
formals(.FUN)[[names(args)[i]]] <<- args[[i]]
}))
.FUN
}
# Now Try It
.paste <- hijack(paste, collapse = "_FOO_")
.paste(1:5)
.paste(1:5, LETTERS[1:5], sep="_BAR_")
.paste(1:5, collapse=NULL)
Yielding
> .paste(1:5)
[1] "1_FOO_2_FOO_3_FOO_4_FOO_5"
> .paste(1:5, LETTERS[1:5], sep="_BAR_")
[1] "1_BAR_A_FOO_2_BAR_B_FOO_3_BAR_C_FOO_4_BAR_D_FOO_5_BAR_E"
> .paste(1:5, collapse=NULL)
[1] "1" "2" "3" "4" "5"
You could just write a simple wrapper
.paste <- function(..., collapse = "_FOO_"){paste(..., collapse = collapse)}
which gives
> .paste <- function(..., collapse = "_FOO_"){paste(..., collapse = collapse)}
> .paste(1:5)
[1] "1_FOO_2_FOO_3_FOO_4_FOO_5"
> .paste(1:5, collapse = NULL)
[1] "1" "2" "3" "4" "5"