erlicson
erlicson

Reputation: 25

How to define %>% operator?

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

Answers (1)

Konrad Rudolph
Konrad Rudolph

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

Related Questions