管道进入 `if` returns 管道而不对其进行评估

Piping into `if` returns the pipeline without evaluating it

我正在尝试实现一个包含可选步骤 的管道,该步骤由多个函数的管道组成 。它根据条件运行此管道,否则它只是通过原始值。然而,我已经尝试使用 ifpurrr::when 来实现它,但在这两种情况下,积极的情况只是 returns 管道而不是执行它。

这是一个简单的人为示例。我已将条件管道简化为只有一个函数,但能够在 TRUE 分支内使用 magrittr 管道在这里很重要。

library(magrittr)

maybe_round = function(x, round = TRUE){
  x %>%
    `if`(
      round,
      . %>% round(),
      .
    )
}
> maybe_round(5.3, TRUE)
Functional sequence with the following components:

 1. round(.)

Use 'functions' to extract the individual functions. 
> maybe_round(5.3, FALSE)
[1] 5.3

第二种情况运行正常;它返回原始值不变。但是第一种情况不是,它返回了 magrittr 管道,但实际上并没有用 5 喂养它。我怎样才能让它按我的意图工作?我认为这与 magrittr 重写语法树的方式有关,但我不太明白。

只是不要在 `if`() 中再次使用管道。

maybe_round = function(x, round = TRUE){
  x %>%
    `if`(
      round,
      round(.),
      .
    )
}

maybe_round(5.3, TRUE)
# [1] 5
maybe_round(5.3, FALSE)
# [1] 5.3

语法 . %>% round(.) 表示 function(.) round(.)。任何时候 dot 启动一个管道它都会定义一个函数而不是一个普通的管道。将圆点括起来以防止圆点开始内部管道。

 maybe_round = function(x, round = TRUE){
   x %>%
     `if`(
       round,
       (.) %>% round(),
       .
     )
 }

maybe_round(5.3, TRUE)
## [1] 5

另一种可能性是将其保留为一个函数,然后像这样在外点计算该函数:

 maybe_round = function(x, round = TRUE){
   x %>%
     `if`(
       round,
       (. %>% round())(.),
       .
     )
 }

这与 `if` 无关——同样的问题会出现在任何其他功能上。事实上,问题出在 . %>% … 表达式,它 不是正常的管道 。相反,这种特殊语法会创建一个 lambda(请参阅“将点占位符用作 lhsin the documentation)。

如果你坚持在这里使用管道,你需要先将.分配给一个不同的变量名,例如:

maybe_round = function(x, round = TRUE){
  x %>%
    `if`(
      round,
      {
          x = .
          x %>% round()
      },
      .
    )
}

…老实说,我会使用常规 if 表达式并将其封装在一个可以通过管道输入的函数中,即

maybe_round = function (x, round = TRUE) {
    x %>% maybe_round_impl(round)
}

maybe_round_impl = function (x, round = TRUE) {
    if (round) {
        x %>% round()
    } else {
        x
    }
}