Bizarro管道->.;是否有不推荐使用的缺点?

从 R-Version 4.1.0 开始,管道|>处于稳定版本。当将 lhs 传递给第一个参数以外的参数时,手册的示例显示:

mtcars |> subset(cyl == 4) |> (function(d) lm(mpg ~ disp, data = d))()

或使用时 (x)

mtcars |> subset(cyl == 4) |> ((d) lm(mpg ~ disp, data = d))()

或者使用当前需要激活的PIPEBIND

Sys.setenv(`_R_USE_PIPEBIND_` = TRUE) 
mtcars |> subset(cyl == 4) |> . => lm(mpg ~ disp, data = .)

|>也可以使用Bizarro 管道 代替->.;

mtcars |> subset(cyl == 4) ->.; lm(mpg ~ disp, data = .)

由于 R 中管道符号的一个目的是允许以一种可能使处理步骤序列 更容易遵循的方式编写嵌套的调用序列,至少对我来说,这也由->.;. Bizarro 管道并不是真正的管道,但对我来说,它目前是一个受欢迎的替代方案,|>尤其是在将 lhs 传递到第一个参数以外的参数的情况下。但是在使用它时,我得到了不使用它的评论。

所以我想知道Bizarro管道是否有建议不要使用它的缺点?


到目前为止,我看到它.在环境中创建或覆盖并保留此引用,这将强制修改副本。但是当调用一个函数时,参数中有数据,也会创建对这个数据的引用。当使用for循环时,使用var后保持不变。

for(i in iris) {}
tracemem(i) == tracemem(iris[[ncol(iris)]])
#[1] TRUE

同样对于性能,它显示出的缺点并不多:

x <- 42
library(magrittr)
Sys.setenv(`_R_USE_PIPEBIND_` = TRUE) 
#Nonsense operation to test Performance
bench::mark(x
, identity(x)
, "x |> identity()" = x |> identity()
, "x |> ((y) identity(y))()" = x |> ((y) identity(y))()
, "x |> . => identity(.)" = x |> . => identity(.)
, "x ->.; identity(.)" = {x ->.; identity(.)}
, x %>% identity
)
#  expression                     min   median `itr/sec` mem_alloc `gc/sec` n_itr
#  <bch:expr>                <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int>
#1 x                          60.07ns  69.03ns 13997474.        0B      0   10000
#2 identity(x)               486.96ns 541.91ns  1751206.        0B    175.   9999
#3 x |> identity()           481.03ns 528.06ns  1812935.        0B      0   10000
#4 x |> ((y) identity(y))() 982.08ns   1.08µs   854349.        0B     85.4  9999
#5 x |> . => identity(.)     484.06ns 528.06ns  1815336.        0B      0   10000
#6 x ->.; identity(.)        711.07ns 767.99ns  1238658.        0B    124.   9999
#7 x %>% identity              2.86µs   3.23µs   294945.        0B     59.0  9998

回答

奇异管道的主要问题是它会产生隐藏的副作用,并且更容易产生细微的错误。它降低了代码的可维护性。

.变量的持久存在使得以后很容易意外地引用这个值:如果你在某个时候忘记赋值并认为你做了,它的存在会掩盖错误。很容易排除这种可能性,但此类错误相当普遍,更糟糕的是,非常不明显:您不会收到错误消息,只会得到错误的结果。相比之下,如果您在某处忘记了管道符号,则会立即收到错误消息。

更糟糕的是,奇怪的管道以两种不同的方式隐藏了这种容易出错的副作用。首先,因为它使分配不明显。我认为以前是->分配不应该使用,因为左到右分配隐藏了一个副作用,并且副作用应该进行语法明显。这种情况下的副作用是赋值,它应该发生在它最突出的地方:在表达式的第一列中,而不是隐藏在它的末尾。这是对使用->(或任何其他试图掩盖副作用的尝试)的根本反对,不仅限于奇异的管道。

而且因为.默认情况下是隐藏的(从lsIDE 中的检查器窗格和从它的检查器窗格),这使得意外依赖它变得更加容易。

因此,如果您想分配一个临时名称而不是使用管道,只需这样做。但:

  1. 执行从右到左的赋值,即使用name = valueor name <- valuenot value -> name
  2. 使用描述性名称。

我再怎么强调也不为过,这是微妙错误的实际来源——不要低估它!

另一个问题是它的使用破坏了编辑器对自动格式化代码的支持。在某些 IDE 中,这是通过插件“可解决的问题”,但实际上,该解决方案解决了一个本不应该存在的问题。为了澄清我的意思,如果您使用的是奇怪的管道,您大概需要一个悬挂的缩进,即沿着这些线的东西:

mtcars ->.
  subset(cyl == 4) ->.
  lm(mpg ~ disp, data = .)

……但是自动缩进不会像这样缩进代码,并且自动格式化程序会展平悬挂的缩进。

这些问题都不是禁止的(尽管第一个非常严重);但在不存在正参数的用于使用比扎罗管他们果断地打破平衡。毕竟,奇怪的管道解决了哪些问题不能通过适当的管道操作符1或常规赋值来更好地解决?如果您不能使用 R 4.1,请使用“magrittr”。如果您不喜欢 'magrittr' 的语义,请编写您自己的管道运算符,使用许多其他现有实现之一,或者仅使用常规赋值。

最后,有人可能会争辩说,这段代码非常不寻常,足以让读者感到困惑,但老实说,如果用法是一致的并且在某处清楚地记录在案,我认为这不是一个非常有说服力的论点。但它提出了另一个反对向初学者推荐使用它的论据。


1当然,这很容易回答:|>不允许显式点替换。虽然我理解反对支持它的论点,但它的缺失鼓励了诸如 bizarro pipe 之类的黑客行为这一事实是一个非常有力的论据,即这实际上是一个巨大的错误。


以上是Bizarro管道-&gt;.;是否有不推荐使用的缺点?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>