1

I'd like to create a few functions that do slightly different things and that can each accept a global variable.

I use assign to assign the function this_value to the name it should have, this_key. The three functions it should create are func_a, func_b, and func_c.

Each newly minted function should be able to take an input x and do something particular to that function to x; in this case, print "key_name: name ----- value_x: x". So name should depend on whether the function is func_a, func_b, or func_c; e.g., calling func_a should give us "key_name: a".

to_name <- c("a", "b", "c")

create_funcs <- function() {
  all_funcs <- list()

  for (name in to_name) {
    this_key <- paste0("func_", name)

    this_value <<- function(x) { 
      paste0("key_name:  ", name, " -----  value_x: ", x)
    }
    assign(this_key, this_value, envir = .GlobalEnv) 

    all_funcs <- c(all_funcs, this_key)
  }
  return(all_funcs)
}

create_funcs()

However, after creating the functions, they each only return a name of "c", or the last value in the vector to_name.

func_a("foo")  # key_name:  c -----  value_x: foo
func_b("bar")  # key_name:  c -----  value_x: bar

Instead, func_a("foo") should return "key_name: a ----- value_x: foo".

For what it's worth, this works in a similar object-assigning function:

create_objects <- function() {
  all_objs <- list()

  for (name in to_name) {
    this_key <- paste0("key_", name)

    this_value <- paste0("value_", name)

    assign(this_key, this_value, envir = .GlobalEnv)

    all_objs <- c(all_objs, this_key)
  }
  return(all_objs)
}

create_objects()

Example:

key_a  # value_a

Thanks for taking a look!

1 Answer 1

1

I'm not entirely sure if this solves your problem, since your real use case is probably more complicated than this reproducible example. But you might want to check out purrr::partial.

Here's a possible solution I came up with using that function.

library(purrr)

func_ <- function(x, key_name) {
  paste0("key_name:  ", key_name, " -----  value_x: ", x)
}


func_a <- partial(func_, key_name = "a")

func_a("foo")

#> [1] "key_name:  a -----  value_x: foo"


assign("func_b", partial(func_, key_name = "b"))

func_b("foo")

#> [1] "key_name:  b -----  value_x: foo"

EDIT:

Here you can just take and character vector and iterate over each element (like with a for loop) using purrr::walk to create a new function for each one. You just have to make sure to set the environment to .GlobalEnv in the assign() call. I don't know that much about environment scoping for things like this, and feel like I've read that this can sometimes be a bad idea, but it seems to do what you described. Hope this helps.

letters %>% walk(~ assign(x = paste0("func_", .x),
                          value = partial(func_, key_name = .x),
                          envir = .GlobalEnv))

func_x("foo")

#> [1] "key_name:  x -----  value_x: foo"
Sign up to request clarification or add additional context in comments.

6 Comments

The one thing is I still would like to be able to do the assignment within the for loop so I don't have to name each function individually outside the function. Something like this all_funcs <- c(all_funcs, partial(func_, name = name, envir = .GlobalEnv)) gives the same result as above (i.e., func_a("foo") # key_name: c ----- value_x: foo)
@amanda I've edited the answer to add an example of creating multiple functions like this with a loop. Hope it's helpful
perfect, thanks a ton. guess I'd better get on the purrr train!
@amanda Glad it was helpful. Yeah, purrr is great - in addition to purrr.tidyverse.org, you might want to check out this chapter in R for Data Science
totally, you've convinced me that the end of this chapter is even more useful than the beginning. fantastic book. if you're interested in how your solution is being put to use you'll find it in construct_funcs.R here github.com/aedobbyn/beer-data-science. still early stages so nothing much to show yet but hoping to knit some of it together soon!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.