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!

amanda
  • 321
  • 5
  • 12

1 Answers1

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"
austensen
  • 2,857
  • 13
  • 24
  • 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 May 28 '17 at 15:08
  • @amanda I've edited the answer to add an example of creating multiple functions like this with a loop. Hope it's helpful – austensen May 29 '17 at 02:07
  • perfect, thanks a ton. guess I'd better get on the `purrr` train! – amanda May 29 '17 at 23:06
  • @amanda Glad it was helpful. Yeah, `purrr` is great - in addition to [purrr.tidyverse.org](http://purrr.tidyverse.org/), you might want to check out this [chapter in R for Data Science](http://r4ds.had.co.nz/iteration.html) – austensen May 29 '17 at 23:11
  • 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 https://github.com/aedobbyn/beer-data-science. still early stages so nothing much to show yet but hoping to knit some of it together soon! – amanda May 30 '17 at 03:28
  • That looks like a cool project, thanks for sharing. I'll keep an eye out to see how it goes. – austensen May 30 '17 at 03:51