unquote (!!) arguments in purrr::as_mapper()

Hi.

I created a mapper function using purrr::as_mapper() which converts tbl numeric vars into log values. It takes 3 arguments :1) a tbl 2) frac : a numeric value to be added before applying log and 3) a positive number with respect to which log are computed.
See the reproducible example below. The function is working as expected.

My question is

  1. Why do I need to unquote arguments 2 and argument 3 (!!..2 and !!..3 ) inside mutate_if and not argument 1 (..1) ?

  2. While calling the mapper function, why do any random names assigned to arguments 1 and 2 works ?


library(tidyverse)
log_tbl <- purrr::as_mapper(~ (..1 %>% dplyr::mutate_if(is.numeric , ~ log(. +  !!..2 ,base = !!..3) )))
tbl <- tibble::tibble(x = letters[1:5] , y = LETTERS[1:5] , z = 1:5 )
tbl
#> # A tibble: 5 x 3
#>   x     y         z
#>   <chr> <chr> <int>
#> 1 a     A         1
#> 2 b     B         2
#> 3 c     C         3
#> 4 d     D         4
#> 5 e     E         5

tbl %>% log_tbl(0.1 , 2)
#> # A tibble: 5 x 3
#>   x     y         z
#>   <chr> <chr> <dbl>
#> 1 a     A     0.138
#> 2 b     B     1.07 
#> 3 c     C     1.63 
#> 4 d     D     2.04 
#> 5 e     E     2.35

tbl %>% log_tbl(frac = 0.1 , base= 2)
#> # A tibble: 5 x 3
#>   x     y         z
#>   <chr> <chr> <dbl>
#> 1 a     A     0.138
#> 2 b     B     1.07 
#> 3 c     C     1.63 
#> 4 d     D     2.04 
#> 5 e     E     2.35

Created on 2019-10-22 by the reprex package (v0.3.0)

Hi @cparsania. You question is a little complicated. I try my best to make it clear.

The !! is not for as_mapper, it is for mutate_if. It uses to trigger the evaluation of ..2 and ..3 in a quoted expression in non standard evaluation.
Why ..1 not need unquote because as_mapper is just like extract function. It map your function

~ (..1 %>% dplyr::mutate_if(is.numeric , ~ log(. +  !!..2 ,base = !!..3) ))

to an only argument ellipsis ... with the arguments like this

function (..., .x = ..1, .y = ..2, . = ..1)

..1 means the first element in ellipsis. ..2 means the second element and so on. So, ..1 is evaluated as standard evaluation and no need unquote.

As the above, because all variables pass to the function as ellipsis. So, no matter what name you give to the argument, we can retrieve the value of the first element of ellipsis with ..1, the second element of ellipsis with ..2 and the third element of ellipsis with ..3.

P.S. You can also you .x and . to retrieve the first element of the ellipsis and .y for the second element.

Hope I can make myself clear and can help.

1 Like

Thanks @raytong. Your explanation helped me to understand what is standard and non standard evaluations.

with regard to following statement

The confusing part was although I do not quote them (..2 and ..3) explicitly (using rlang::enexpr() or rlang::ensym() )why do I need to unquote them ? However, reading chapter 18 and 19 from @hadley's Advanced R helped to clear out many doubts.

breaking down purrr::as_mapper() to independent function helped to understand more clearly how quoting and unquoting works.

yy <- function (... , .x = ..1, .y = ..2, . = ..1) {
        
        ff <- function(...){ 

                log(..1 + ..2, base = ..3)  
            
        }
        
        (..1 %>% dplyr::mutate_if(is.numeric,  ~ff(..1 = . , ..2 = !!..2, ..3 = !!..3) ))
        
}
1 Like

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.