为什么在函数内部使用`coalesce`时才能与`across`一起工作?

huangapple go评论125阅读模式
英文:

why does across work with coalesce only when inside a function?

问题

在函数内部使用 across() 可以正常工作,但在函数外部使用时会出现错误。这是为什么呢?谢谢!

Note: This is the translated code portion, and I will not provide an answer to your question as per your request.

英文:

Little tidyeval question, I've got this function:

coacross <- function(...) {
  coalesce(!!!across(...))
}

And then if I do something like this:

aa = tibble(a1 = c(NA, 1), a2 = c(2, NA), b = 3:4) %>% 
mutate(a_full = coacross(starts_with('a')))

Works like a charm. But if I do the same outside a function, I get an error:

aa %>% mutate(c = coalesce(!!!across(starts_with('a'))))


Error in `across()`:
! Must only be used inside data-masking verbs like `mutate()`, `filter()`, and
  `group_by()`.

What gives? I'm a bit lost here. Thanks!

答案1

得分: 4

你已经到达了整洁评估编程的晦涩一面 :-/

问题在于 !!! 在支持注入操作符的第一个动词中被非常早地评估:

  • 在你的第一个示例中,在 mutate() 调用中没有注入。相反,!!! 是在 coacross() 内的 coalesce() 调用触发的,因此时机是正确的。

  • 在你的第二个示例中,!!!mutate() 调用中触发。注入是发生的第一件事,这意味着 mutate() 还没有足够的时间来设置 across() 需要的数据屏蔽上下文,因此时机太晚了。

为了解决这个问题,必须消除注入上下文之间的重叠。这就是你通过将 !!! 移动到另一个函数中所做的。另一种方法是注入对 coalesce() 的调用,但这相当丑陋且很难理解:

aa |> mutate(c = !!quote(coalesce(!!!across(starts_with('a')))))

我更喜欢你的 coacross() 解决方案。

英文:

You've reached the obscure side of tidy eval programming :-/

The problem is that !!! is evaluated very early by the first verb that happens to support injection operators:

  • In your first example, there isn't any injection in the mutate() call. Instead, !!! is triggered at the coalesce() call inside coacross(), and so the timing is correct.

  • In your second example, !!! is triggered at the mutate() call. Injection is the very first thing that happens, which means that mutate() hasn't had time yet to set up the data-masking context that across() needs, and so the timing is too late.

To work around this the overlap between injection contexts must be removed. This is what you did by moving the !!! in another function. An alternative is to inject a call to coalesce() but that's rather ugly and very hard to understand:

aa |> mutate(c = !!quote(coalesce(!!!across(starts_with('a')))))

I prefer your coacross() solution.

huangapple
  • 本文由 发表于 2023年6月1日 05:42:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76377486.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定