1

I've taken quasiquotation to a top level. I'm close to getting my master-quasiquotator badge (see edits below). There's one chellenge bit left.

Using different inputs to create quosures with dplyr. The end result is:

the_quote <- quo( if_else(!!cond_expr, !!inter_quo, !!var_expr) )

And I have managed to construct expressions above from a customized table with character strings, like this:

var_expr <- as.name(rules_df$target_col)

cond_expr <- "make == '%s'" %>% sprintf(rules_df$context_col) %>% parse_expr()

inter_quo <- quo( 
    str_detect( !!var_expr, regex(!!rules_df$phrase_col) ))

And where context_col, phrase_col, target_col are string columns in a table that I've defined the rules of engagement.

Example:

rules_df <- data_frame(
    context_col = "BMW", 
    phrase_col  = "Serie X(\\d)", 
    target_col  = "model")

cars_table <- data_frame(
    make = c("Mercedes", "BMW", "BMW"), 
    model = c("Viano", "Serie X5", "Z4"))

Tells me to find those BMW's as Serie X5 , which I would later replace with just X5 but that's another story.

On printing the quote, I noticed that the expressions work well, but intermediate quosure is giving an error.

> the_quote
<quosure>
  expr: ^if_else(marca == "BMW", 
            ^str_detect(model, regex("Serie X(\d)")), model)
  env:  000000002001DEE0

> mutate(cars_table, detect = !!the_quote)
Error: Evaluation error: `false` must be type logical, not character.

In the quosure I have an extra ^ which is converting the result of str_detect into a character.

How do I integrate this intermediate quosure into the outside one?

Thanks.

Edit

Upon reviewing the solution, it ends up that the issue in this challenge was not quotation, but using if_else correctly in detect column. That is changing logical into character, or just having the false clause act accordingly.

Thus, the alternative solution is to set if_else(!!cond_expr, !!inter_quo, FALSE) from the beginning.

Community
  • 1
  • 1
Diego-MX
  • 2,279
  • 2
  • 20
  • 35
  • I get some errors while copy/pasting your code. What is `context_col`. also, the `rules_df` is giving errors `Error: '\d' is an unrecognized escape in character string starting ""Serie X(\d"` – akrun Mar 15 '19 at 14:45
  • I fixed the example, and completed the code to replicate it. Kept it from top to bottom, to follow the logic. Hope that's not too bad. – Diego-MX Mar 15 '19 at 14:55
  • 2
    The issue would be that `str_detect` return `logical` and 'model' is character` `if_else` needs both to be same class – akrun Mar 15 '19 at 15:23
  • You can chek with `cars_table %>% mutate(detect = if_else(make == "BMW", as.character(str_detect(model, regex("Serie X\\d"))), model))` and without the `as.character` – akrun Mar 15 '19 at 15:24
  • What is the desired output here if this were to work? You can't have mixed types in an atomic vector in R. – MrFlick Mar 15 '19 at 15:26
  • Aaahhh!! Doesn't have to do with quotation, then. – Diego-MX Mar 15 '19 at 15:26
  • @Diego Let me know if the correction works or not – akrun Mar 15 '19 at 15:49

1 Answers1

1

We need to wrap with as.character as the str_detect returns a logical class, while the false parameter of if_else is returning 'character'. The if_else is particular about the class. Thus, if we do

inter_quo <- quo( as.character(str_detect( !!var_expr, 
               regex(!!rules_df$phrase_col) )))

then it should work

mutate(cars_table, detect = !!the_quote)
# A tibble: 3 x 3
#  make     model    detect
#  <chr>    <chr>    <chr> 
#1 Mercedes Viano    Viano 
#2 BMW      Serie X5 TRUE  
#3 BMW      Z4       FALSE 
akrun
  • 874,273
  • 37
  • 540
  • 662