Search code examples
rif-statementtidyversemagrittr

Why does pipe inside if() function fail when first argument is referred with a '.'


I spent 45 mins to get a very simple if() inside a loop to work, but I want to understand why it was failing in the first place.

It's a simple R Magrittr pipe chain with a if() condition in braces {}

Here's the simplified reprex (reproducible example)

library(tidyverse) # load tidyverse library

a <- tibble(a1 = 1:6, a2 = 6:1, a3 = rep(c('a', 'b'),3), a4 = as_factor(5:10))

# function to check the data type of a column

# Fails
check1 <- function(.df, .colm)
{
  .df %>%
     { if(. %>% pull(var = {{.colm}}) %>% is.character()) 1 else 2} # pull .colm from .df and check if is char

}

# Works
check2 <- function(.df, .colm)
{
  .df %>%
    {if(pull(., var = {{.colm}}) %>% is.character()) 1 else 2} # pull .colm from .df and check if is char
  
}

check1(a, a1) # Fails
#> Error in if (. %>% pull(var = {: argument is not interpretable as logical
check2(a, a1) # Works
#> [1] 2

Created on 2021-03-30 by the reprex package (v0.3.0)

Also do let me know if there's a simpler way to check the class() of a column in a data frame that can be generalized to have the column name taken from user input to a funtion


Solution

  • There are two problems:

    1. both the calls to check1 and check2 give errors because their inputs have not been defined

    2. a magrittr pipeline that begins with just a dot on the left hand side defines a function so in the first case the part within the condition portion of the if is defining a function, not a logical condition.

       library(magrittr)
      
       f <- . %>% { . ^ 2 }
       f(3)
       ## [1] 9
      

    This fails for the same reason

          library(purrr)
          library(dplyr)
    
          BOD %>% { if (. %>% pull("demand") %>% is.numeric) 1 else 0 }
    

    but this works since the left hand side is now (.) instead of just .

          BOD %>% { if ( (.) %>% pull("demand") %>% is.numeric) 1 else 0 }