Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

for loop produces different result as map due to lazy evaluation #3

Open
TimTeaFan opened this issue Apr 4, 2022 · 2 comments
Open
Assignees
Labels
feature next major release will be implemented in next major release

Comments

@TimTeaFan
Copy link
Owner

TimTeaFan commented Apr 4, 2022

R's lazy evaluation can lead to different results when translating map function calls to for loops. Below is one example that Claus Wilke provided on Twitter.

Lets think about, whether there is someway to force evaluation programmatically to produce the same result as map and if not, this needs to be mentioned an a vignette together with other caveats and quirks of as_loop().

library(loopurrr)
#> Loading required package: purrr

make_add <- function(n) {
  function(x) {
    x + n
  }
}

idx <- as.list(1:5)

z <- map(idx, make_add)

map(idx, make_add) %>% 
   as_loop()

# --- convert: `map(idx, make_add)` as loop --- #
out <- vector("list", length = length(idx))

for (i in seq_along(idx)) {
  out[[i]] <- make_add(idx[[i]])
}
# --- end loop --- #

z[[1]](10)
#> [1] 11
out[[1]](10)
#> [1] 15

Created on 2022-04-05 by the reprex package (v0.3.0)

@TimTeaFan
Copy link
Owner Author

TimTeaFan commented Apr 5, 2022

One possible way to modify the loop to make it work would be to wrap the rewritten function in eval(bquote()) and evaluate every input with .().

# --- convert: `map(idx, make_add)` as loop --- #
out <- vector("list", length = length(idx))
for (i in seq_along(idx)) {
  
  out[[i]] <- eval(bquote(
    
    make_add(idx[[.(i])])
    
    ))
}
# --- end loop --- #

@TimTeaFan
Copy link
Owner Author

TimTeaFan commented Apr 19, 2022

Here is a more realistic example of lazy evaluation in a ggplot for loop.

library(ggplot2)
out <- vector("list", length = 4)

for (i in 1:4) {
  out[[i]] <- ggplot(iris, aes(x = iris[, i])) + geom_histogram(binwidth = 1)
}


# Another alternative to `eval(bquote())` is using `local()` and self-assign `i`:
for (i in 1:4) {
  out2[[i]] <- local({
    i <- i 
    ggplot(iris, aes(x = iris[, i])) + geom_histogram(binwidth = 1)
  })
}

@TimTeaFan TimTeaFan added the next major release will be implemented in next major release label Sep 4, 2022
@TimTeaFan TimTeaFan self-assigned this Sep 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature next major release will be implemented in next major release
Projects
None yet
Development

No branches or pull requests

1 participant