我想定义一个函数,使magrittr
管道运算符默认情况下将对象传递给第二个参数。
library(magrittr)
foo <- function(a, b) c(a,b)
管道运算符将对象传递给foo
的第一个参数。
1 %>% foo(2)
使用.
占位符时,管道将对象传递给foo的第二个参数。
1 %>% foo(2, .)
是否可以构建函数,使其在其定义中直接具有.
占位符,
以便管道默认使用第二个参数?在伪代码中,这将是
类似于:
foo2 <- function(a, b = <pipe arg placeholder>) {
b = <process arg placeholder>
c(a, b)
}
答案 0 :(得分:1)
在此示例中,管道的输入用作verilator/README
的第二个参数。我们确实必须使用{...},但这也许已经足够接近了。
f
答案 1 :(得分:1)
问题是foo
不“知道”管道的写法
它只知道一旦 magrittr 添加了点(如果相关),该如何调用
因此,根据函数本身,我们无法区分隐式点和显式点。
除了这个问题之外,如果第一个参数是点,我们可以切换两个第一个参数,然后返回经过评估的修改后的调用:
library(magrittr)
foo <- function(a, b) {
mc <- match.call()
if(mc[[2]] == quote(.)) {
mc[[2]] <- mc[[3]]
mc[[3]] <- quote(.)
return(eval.parent(mc))
}
c(a,b)
}
1 %>% foo(2)
#> [1] 2 1
1 %>% foo(2, .)
#> [1] 2 1
# but also, because of disclaimer above
1 %>% foo(., 2)
#> [1] 2 1
由reprex package(v0.3.0)于2019-10-09创建
如果a
可以采用默认值并将其留空,则可能需要进行调整。
edit:当我说foo
不知道管道的编写方式时,我撒谎了,它在调用堆栈中,我们可以通过在函数中调用sys.call()
来看到它,但是我认为解决方案是如此复杂!
另一种方法是定义插入第二个位置的管道,它稍微灵活一些,也许也就不那么令人惊讶了:
foo <- function(a=2, b) {
c(a,b)
}
`%>2%` <-
function (lhs, rhs) {
rhs_call <- insert_dot2(substitute(rhs))
eval(rhs_call, envir = list(. = lhs), enclos = parent.frame())
}
insert_dot2 <-
function(expr, special_cases = TRUE) {
if(is.symbol(expr) || expr[[1]] == quote(`(`)) {
# if a symbol or an expression inside parentheses, make it a call with
# a missing first argument and a dot on second position
expr <- as.call(c(expr,alist(x=)[[1]], quote(`.`)))
} else if(length(expr) ==1) {
# if a call without arg, same thing
expr <- as.call(c(expr[[1]],alist(x=)[[1]], quote(`.`)))
} else if (expr[[1]] != quote(`{`) &&
all(sapply(expr[-1], `!=`, quote(`.`)))) {
# if a call with args but no dot in arg, insert dot in second place first
expr <- as.call(c(as.list(expr[1:2]), quote(`.`), as.list(expr[-(1:2)])))
}
expr
}
1 %>2% foo(2)
#> [1] 2 1
1 %>2% foo(2, .)
#> [1] 2 1
1 %>2% foo(., 2)
#> [1] 1 2
1 %>2% foo()
#> [1] 2 1
由reprex package(v0.3.0)于2019-10-09创建
注意:用管道输送到第二位有点奇怪,我宁愿用管道输送到最后(对于您的问题的示例,结果将是相同的),如果您想通过管道输送到最后,则可以:
foo <- function(a=2, b) {
c(a,b)
}
`%>last%` <-
function (lhs, rhs) {
rhs_call <- insert_dot_last(substitute(rhs))
eval(rhs_call, envir = list(. = lhs), enclos = parent.frame())
}
insert_dot_last <-
function(expr, special_cases = TRUE) {
if(is.symbol(expr) || expr[[1]] == quote(`(`)) {
# if a symbol or an expression inside parentheses, make it a call with
# a dot arg
expr <- as.call(c(expr, quote(`.`)))
} else if(length(expr) ==1) {
# if a call without arg, same thing
expr <- as.call(c(expr[[1]], quote(`.`)))
} else if (expr[[1]] != quote(`{`) &&
all(sapply(expr[-1], `!=`, quote(`.`)))) {
# if a call with args but no dot in arg, insert dot in last place
expr <- as.call(c(as.list(expr), quote(`.`)))
}
expr
}
1 %>last% foo(2)
#> [1] 2 1
1 %>last% foo(2, .)
#> [1] 2 1
1 %>last% foo(., 2)
#> [1] 1 2
由reprex package(v0.3.0)于2019-10-09创建