-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
A code snippet like this
dplyr::recode_factor(x, !!! layer_key)produces an error that says !level_key is an invalid argument type
This is the result of a question on https://community.rstudio.com/t/using-recode-factor-with-quasi-quotation/5761/5
Here is a repro
library(magrittr)
library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#> filter, lag
#> The following objects are masked from 'package:base':
#>
#> intersect, setdiff, setequal, union
set.seed(100)
x <- sample(head(LETTERS, 3), 10, replace = TRUE) %>% factor
x
#> [1] A A B A B B C B B A
#> Levels: A B C
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A")) # set factor re-level
level_key2 <- list(B = "Be", C = "Cool", A = "Amigo")
dplyr::recode_factor(x, !!!level_key)
#> Error in !level_key: invalid argument typeCreated on 2018-03-03 by the reprex package (v0.2.0).
The problem is the use of c(...) inside of rcode_factor. Here is my analysis of the problem.
The problem is buried inside of recode_factor. It is that only functions that are implemented to use quosures can properly interpret !!!
Here is where the problem is in recode_factor:
dplyr:::recode_factor
#> function (.x, ..., .default = NULL, .missing = NULL, .ordered = FALSE)
#> {
#> recoded <- recode(.x, ..., .default = .default, .missing = .missing)
# ----------------------------The . problem is with c() ----
#> all_levels <- unique(c(..., recode_default(.x, .default,
#> recoded), .missing))
#> recoded_levels <- if (is.factor(recoded))
#> levels(recoded)
#> else unique(recoded)
#> levels <- intersect(all_levels, recoded_levels)
#> factor(recoded, levels, ordered = .ordered)
#> }
#> <environment: namespace:dplyr>Created on 2018-03-03 by the reprex package (v0.2.0).
The problem is in the Combine, c(), function. Although in !!! layer_key !!! looks like an operator or in !!!(layer_key) it looks like a function it is neither.
It depends on the function getting the !!! layer_key in an ... argument to do something like enquo(...) so that standard evaluation is bypassed. It is enquo(or one of it's friends) that interprets !!! to turn a list into individual dot arguments.
But c() is a primitive function so it just does standard evaluation of !!! level_key which, in effect, produces a syntax kind of error.
Here is an example of a function that tries to use !!! with c()
suppressPackageStartupMessages(library(tidyverse))
f2 <- function(...) {
c(...)
}
level_key <- list("Be", "Cool", "Amigo") %>% set_names(c("B", "C", "A")) # set factor re-level
f2(!!! level_key)
#> Error in !level_key: invalid argument typeCreated on 2018-03-03 by the reprex package (v0.2.0).
I don't see a workaround for this.