Skip to content

Instantly share code, notes, and snippets.

@dmi3kno
Created January 17, 2023 19:44
Show Gist options
  • Save dmi3kno/f44f72d571246b7c09247e8a5699a535 to your computer and use it in GitHub Desktop.
Save dmi3kno/f44f72d571246b7c09247e8a5699a535 to your computer and use it in GitHub Desktop.
Function factory with changeable argument name
library(magrittr)
logit <- function(u) log(u)-log(1-u)
raise_to_pow <- function(fun, pname_pow=".pow"){
eval(parse(text=gsub(pattern=".pow", replacement=pname_pow,
"function(u, .pow=1, ...) fun(u,...)^(.pow)")))
}
powlogit <- logit %>% raise_to_pow(pname_pow="e")
powlogit(0.2,e=2)
#[1] 1.921812
logit(0.2)^2
#[1] 1.921812
@moodymudskipper
Copy link

moodymudskipper commented Jan 18, 2023

Here are 3 options:

raise_to_pow <- function(fun, pname_pow=".pow") {
  formals_ <- alist(u=, .pow=1, ...=)
  names(formals_)[names(formals_) == ".pow"] <- pname_pow
  body_ <- substitute(fun(u,...)^(.pow), list(.pow = as.symbol(pname_pow)))
  as.function(c(formals_, body_))
}

raise_to_pow <- function(fun, pname_pow=".pow") {
  formals_ <- alist(u=, .pow=1, ...=)
  names(formals_)[names(formals_) == ".pow"] <- pname_pow
  body_ <- bquote(fun(u,...)^(.(as.symbol(pname_pow))))
  as.function(c(formals_, body_))
}

raise_to_pow <- function(fun, pname_pow=".pow") {
  formals_ <- alist(u=, .pow=1, ...=)
  body_ <- quote(fun(u,...)^(.pow))
  names(formals_)[names(formals_) == ".pow"] <- pname_pow
  body_ <- do.call(substitute, list(body_, list(.pow = as.symbol(pname_pow))))
  as.function(c(formals_, body_))
}

@dmi3kno
Copy link
Author

dmi3kno commented Jan 18, 2023

I think the bquote is the least transparent solution. The explicit call construction with do.call has a slight benchmark advantage, so I reused it and expanded for readability (at negligible cost).

raise_to_pow4 <- function(fun, pname_pow=".pow") {
  f <- function(u, .pow=1, ...){
    fun(u,...)^(.pow)
  }
  
  formals_ <- formals(f)
  body_ <- body(f)
  names(formals_)[names(formals_) == ".pow"] <- pname_pow
  body_ <- do.call(substitute, list(body_, list(.pow = as.symbol(pname_pow))))
  as.function(c(formals_, body_))
}

Now I can separate the programming from meta-programming and refactor my functions easily. Thank you very much @moodymudskipper for this!

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