默认情况下,在函数定义中使用 magrittr 点占位符通过管道运算符将对象传递给任意位置的参数?
Use magrittr dot placeholder IN FUNCTION DEFINITION to pass object via pipe operator to argument in arbitrary position by default?
我想以 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)
}
在此示例中,管道的输入用作 f
的第二个参数。我们确实必须使用 {...} 但也许这已经足够接近了。
f <- function(x, y = parent.frame()$.) x - y
12 %>% { f(20) }
## [1] 8
问题是 foo
没有 "know" 管道是如何写的
一旦 magrittr 添加了点(如果相关),它就知道如何调用它
所以从函数本身我们无法区分隐式和显式点。
撇开这个问题不谈,如果第一个参数是点并且 return 评估的修改调用:
,我们可以只切换第一个参数
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
可以采用默认值并留空,以及其他可能的边缘情况,则需要进行调整。
编辑:我说 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 创建
我想以 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)
}
在此示例中,管道的输入用作 f
的第二个参数。我们确实必须使用 {...} 但也许这已经足够接近了。
f <- function(x, y = parent.frame()$.) x - y
12 %>% { f(20) }
## [1] 8
问题是 foo
没有 "know" 管道是如何写的
一旦 magrittr 添加了点(如果相关),它就知道如何调用它
所以从函数本身我们无法区分隐式和显式点。
撇开这个问题不谈,如果第一个参数是点并且 return 评估的修改调用:
,我们可以只切换第一个参数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
可以采用默认值并留空,以及其他可能的边缘情况,则需要进行调整。
编辑:我说 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 创建