Reputation: 25
I need another operator with the same functions as magrittr's %>%.
I tried
"%myop%" <- function(x,f) do.call(f, list(x))
but it doesn't work.
I expect to get my function on the right side solved with the argument from left side, e.g:
> p<-10
> p %>% log()
[1] 2.302585
which is x %>% f and can be rewritten as f(x)
x %>% f(a,b) which can be rewritten as f(x,a,b) -- and this doesn't work
How can I define it?
Upvotes: 1
Views: 76
Reputation: 545528
You can check out the magrittr implementation but, to be fair, the code is quite complex since it does a lot more.
Simply put, to support the semantics you desire you need to extract the unevaluated RHS of the expression and insert the unevaluated LHS into it before evaluating it.
A function call expression is a list that has the function name as its first element, and the rest of its arguments as subsequent elements. So you need to insert the LHS value into that list at the second position.
You then need to turn the resulting list back into a call — as.call
does that:
`%>%` = function (lhs, rhs) {
lhs = substitute(lhs)
rhs = substitute(rhs)
if (is.name(rhs)) {
do.call(as.character(rhs), list(lhs))
} else if (is.call(rhs)) {
rhs = as.list(rhs)
call = as.call(c(rhs[[1L]], list(lhs), rhs[-1L]))
eval.parent(call)
} else {
stop('Unsupported RHS')
}
}
Beware that, since this implementation inserts the unevaluated LHS into the RHS call, a chained pipeline will be evaluated right-to-left. That is, this
(1 : 5) %>% sapply(`*`, 2) %>% sum()
will be transformed into this:
sum(sapply((1: 5), `*`, 2))
before any component is being evaluated.
Upvotes: 1