Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

%>>% pipe for piping last argument #192

Open
vspinu opened this issue Mar 1, 2019 · 5 comments
Open

%>>% pipe for piping last argument #192

vspinu opened this issue Mar 1, 2019 · 5 comments
Labels
feature a feature request or enhancement

Comments

@vspinu
Copy link
Member

vspinu commented Mar 1, 2019

Though not as frequently as piping first argument it's often needed to pipe the last argument.

Would you mind adding the %>>% operator?

x %>>% append(y) # is equivalent to
append(y, x)

>> because in clojure these operators are -> and ->> respectively. Racket uses f> and l>.

@mattmalin
Copy link

That looks like a useful function, but is there an equivalent to ... where it's used in other languages to handle variable arguments which pass through? I can imagine this potentially causing a less defined set of behaviours to capture.

For example, if there's a function foo <- function(x = 1, y = 2, ...) {<function contents>} would z %>>% foo(a) mean foo(a, z) or foo(a, y=2, z) where y=2 comes from missing argument taking default?

@vspinu
Copy link
Member Author

vspinu commented Jul 2, 2019

That's ok. Just like with R where %>% manipulates the code, ->> in lisps is a macro which transforms the code at compile time. So z %>>% foo(a) should be exactly equivalent to foo(a,z).

There is no ability to pass a named argument. Would be great if y = z %>% foo(a) would be transformed into foo(a, y=z). Not sure if it's possible though.

@mattmalin
Copy link

mattmalin commented Jul 2, 2019 via email

@moodymudskipper
Copy link

You could do :

foo <- function(a=2, b) {
  c(a,b)
}

`%>>%` <-
  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 %>>% foo(2)
#> [1] 2 1
1 %>>% foo(2, .)
#> [1] 2 1
1 %>>% foo(., 2)
#> [1] 1 2

See : https://stackoverflow.com/a/58301142/2270475

@hadley hadley added the feature a feature request or enhancement label Apr 20, 2020
@D3SL
Copy link

D3SL commented May 19, 2020

%>>% is already used by pipeR as the primary pipe operator. Plus as mattmalin stated . already allows you to sned input wherever you want. I think rather than another operator it's probably better practice to encourage users to explicitly define where their input is being piped when not to the first unnamed argument.

Apologies for necroposting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature a feature request or enhancement
Projects
None yet
Development

No branches or pull requests

5 participants