Reason for magrittr pipe (%>%) with ifelse behavior?

I use ifelse with pipe in a scenario where I use a redirected result in both state and ifelse. The following is a simplified version: it seems that ifelse + pipe is processing a condition other than . if put inside braces.

 library("magrittr") FALSE %>% ifelse(., 'true', 'false') #> [1] "false" FALSE %>% ifelse(. == TRUE, 'true', 'false') #> Error in ifelse(., . == TRUE, "true", "false"): unused argument ("false") FALSE %>% {ifelse(. == TRUE, 'true', 'false')} #> [1] "false" 

My original goal:

 library("magrittr") NULL %>% ifelse(is.null(.), "", as.character(.)) #> Error in ifelse(., is.null(.), "", as.character(.)): unused argument (as.character(.)) NULL %>% {ifelse(is.null(.), "", as.character(.))} #> [1] "" 

Using {} is good enough for me, but I would like to understand the reasons for this behavior.

Edit: Although this question discusses a related topic, and initially I see the idea of ​​placing ifelse inside curly braces there is no difference between using it simply . or using . into an expression / function call, which is the highlight of my question.

+7
r magrittr
source share
3 answers

The magrittr documentation says that when a dot is used in nested function calls that they lead, as you saw.

Use points for secondary purposes
Often, some attribute or property of lhs is desirable in calling rhs in addition to the lhs value itself, for example. the number of rows or columns. The use of multipoint placeholders several times in an rhs call is quite true, but the design behavior is slightly different when used inside nested function calls. In particular, if a placeholder is used only in a call to a nested function, then lhs will also be placed as the first argument! The reason for this is that in most use cases this gives the most readable code.

For example, iris %>% subset(1:nrow(.) %% 2 == 0) equivalent to iris %>% subset(., 1:nrow(.) %% 2 == 0) , but a bit more compact. This can be reversed by including in braces. For example, 1:10 %>% {c(min(.), max(.))} is equivalent to c(min(1:10), max(1:10)) .

So, the solution that is recommended should actually use curly braces, as you already found.

Logical evaluation, apparently, is a separate function call inside ifelse and therefore the reason why it behaves as such.

+6
source share

I think the error message is pretty clear.

  • When you use {} in {} is replaced by the left side %>% .

  • When you call a function without {} , the first argument is lhs, while the other parameters that you encoded explicitly will move to the right and, in addition, ( see here ):

LHS is required in a position other than the first, you can use dot, '.', As a placeholder.

Therefore, FALSE %>% ifelse(. == TRUE, 'true', 'false') actually calls:

 ifelse(FALSE, FALSE == TRUE, 'true', 'false') 

and FALSE %>% {ifelse(. == TRUE, 'true', 'false')} actually calls:

 ifelse(FALSE == TRUE, 'true', 'false') 
+2
source share

Perhaps this will be more satisfactory for your case:

 NULL %>% as.character %>% inset(length(.)==0, value ="") 
+1
source share

All Articles