将管道输入到 `if` 中会返回该管道而不对其进行评估。

4
我正尝试实现一个具有可选步骤的流程,该步骤由几个函数的流程管道组成。根据条件运行此流程管道,否则它只是通过原始值。但我尝试使用if和purrr::when两种情况来实现这一点,但在两种情况下,正面情况仅返回管道而不执行它。
这里有一个简单的人为例子。我将条件流程简化为一个函数,但能够在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 如何重写语法树有关,但我无法完全理解。

3个回答

1

语法. %>% round(.)表示function(.) round(.)。任何时候,点号开头的管道都定义为函数,而不是普通管道。在点号周围加上括号可以防止点号启动内部管道。

 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())(.),
       .
     )
 }

我认为这是解决magrittr的这个特殊问题最巧妙的方法。 - Migwell

1
这与`if`无关——任何其他函数都会显示相同的问题。实际上,问题在于. %>% ...表达式,它不是一个普通的管道。相反,这种特殊的语法创建了一个lambda(参见文档中的“将点占位符用作lhs)。
如果您坚持要在此处使用管道,您需要先将.分配给另一个变量名,例如:
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
    }
}

非常感谢您对这里发生的事情进行了详细解释。 - Migwell

0

`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

这并没有真正解决我的问题,我想在这里使用管道,因为实际上它是一个非常长的管道。这只是一个简化的例子。 - Migwell
看起来你想做的是在管道内执行与条件无关的所有内容,然后赋值给一个变量。然后使用if语句完成其余部分。如果这是在自定义函数中,请使用逻辑参数来确定是否满足条件。或者,发布更长的代码,我们可以提供解决方案。 - jpenzer
我故意简化了它,因为否则人们会抱怨。你可以轻松地通过将“。%>% round() %>% round() %>% round() %>% round()”作为“TRUE”情况来使管道更长。 - Migwell
我已经展示了运行日志,你可以看到它正常工作。 - G. Grothendieck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接