gpt4 book ai didi

r - 获取在 `magrittr` 管道调用的函数中计算为点的表达式

转载 作者:行者123 更新时间:2023-12-04 15:17:36 25 4
gpt4 key购买 nike

我有一个功能 x_expression()打印传递给参数 x 的表达式.

pacman::p_load(magrittr, rlang)

x_expression <- function(x) {
print(enquo(x))
}

y <- 1

x_expression(y)
#> <quosure>
#> expr: ^y
#> env: global

y %>% x_expression()
#> <quosure>
#> expr: ^.
#> env: 0x7ff27c36a610

所以你可以看到它知道 y被传递给它,但是当 y是通过管道输入的 %>% , 函数返回打印 . .有没有办法恢复 y如果它是通过管道输入的,还是永远消失了?简而言之,我想要的是像 x_expression() 这样的函数但会打印 y在上述两种情况下。

这个问题确实类似于 Get name of dataframe passed through pipe in R ,但它稍微更通用。这个人只想要数据框的名称,我想要表达式,不管它是什么。但是,相同的答案可能适用于两者。我不喜欢这个几乎重复的问题的答案,也不喜欢那个答案的作者。

最佳答案

y不会“永远消失”,因为管道调用了您的函数,并且它也知道 y .有办法恢复y ,但它需要对调用堆栈进行一些遍历。要了解发生了什么,我们将使用 ?sys.frames?sys.calls :

‘sys.calls’ and ‘sys.frames’ give a pairlist of all the active calls and frames, respectively, and ‘sys.parents’ returns an integer vector of indices of the parent frames of each of those frames.



如果我们将这些撒在您的 x_expression() ,我们可以看到当我们调用 y %>% x_expression() 时会发生什么从全局环境来看:
x_expression <- function(x) {
print( enquo(x) )
# <quosure>
# expr: ^.
# env: 0x55c03f142828 <---

str(sys.frames())
# Dotted pair list of 9
# $ :<environment: 0x55c03f151fa0>
# $ :<environment: 0x55c03f142010>
# ...
# $ :<environment: 0x55c03f142828> <---
# $ :<environment: 0x55c03f142940>

str(sys.calls())
# Dotted pair list of 9
# $ : language y %>% x_expression() <---
# $ : language withVisible(eval(...
# ...
# $ : language function_list[[k]...
# $ : language x_expression(.)
}

我用 <--- 突出显示了重要的部分.请注意, enquo 捕获的 quosure位于函数的父环境中(从堆栈底部算起第二个),而管道调用知道 y一直在堆栈的顶部。

有几种方法可以遍历堆栈。 @MrFlick's answer到类似的问题以及 this GitHub issuesys.frames() 遍历框架/环境.在这里,我将展示一个遍历 sys.calls() 的替代方案。并解析表达式以找到 %>% .

难题的第一部分是定义一个将表达式转换为其 Abstract Sytax Tree(AST) 的函数。 :
# Recursively constructs Abstract Syntax Tree for a given expression
getAST <- function(ee) purrr::map_if(as.list(ee), is.call, getAST)
# Example: getAST( quote(a %>% b) )
# List of 3
# $ : symbol %>%
# $ : symbol a
# $ : symbol b

我们现在可以系统地将此功能应用于整个 sys.calls()堆。目标是识别第一个元素是 %>% 的 AST。 ;然后,第二个元素将对应于管道的左侧( symbol a 示例中的 a %>% b)。如果有多个这样的 AST,那么我们就在一个嵌套的 %>% 中。管道场景。在这种情况下,列表中的最后一个 AST 将是调用堆栈中最低的并且最接近我们的函数。
x_expression2 <- function(x) {
sc <- sys.calls()
ASTs <- purrr::map( as.list(sc), getAST ) %>%
purrr::keep( ~identical(.[[1]], quote(`%>%`)) ) # Match first element to %>%

if( length(ASTs) == 0 ) return( enexpr(x) ) # Not in a pipe
dplyr::last( ASTs )[[2]] # Second element is the left-hand side
}

(小注:我使用 enexpr() 而不是 enquo() 来确保函数在管道内外的行为一致。由于 sys.calls() 遍历返回一个表达式,而不是一个 quosure,我们希望在默认情况下也这样做情况也是如此。)

新函数非常健壮,可以在其他函数中使用,包括嵌套的 %>%管道:
x_expression2(y)
# y

y %>% x_expression2()
# y

f <- function() {x_expression2(v)}
f()
# v

g <- function() {u <- 1; u %>% x_expression2()}
g()
# u

y %>% (function(z) {w <- 1; w %>% x_expression2()}) # Note the nested pipes
# w

关于r - 获取在 `magrittr` 管道调用的函数中计算为点的表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52066097/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com