19

How can you implement F#'s forward pipe operator in R? The operator makes it possible to easily chain a sequence of calculations. For example, when you have an input data and want to call functions foo and bar in sequence, you can write:

data |> foo |> bar

Instead of writing bar(foo(data)). The benefits are that you avoid some parentheses and the computations are written in the same order in which they are executed (left-to-right). In F#, the operator is defined as follows:

let (|>) a f = f a

It would appear that %...% can be used for binary operators, but how would this work?

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
user4
  • 734
  • 1
  • 5
  • 16
  • 6
    It would help a lot if you told us a little more clearly what this operator was actually supposed to do, so we didn't have to go dig up the information for ourselves. Maybe your question states it, but it's a little too telegraphic for me. – Ben Bolker Jan 17 '12 at 15:03

3 Answers3

26

I don't know how well it would hold up to any real use, but this seems (?) to do what you want, at least for single-argument functions ...

> "%>%" <- function(x,f) do.call(f,list(x))
> pi %>% sin
[1] 1.224606e-16
> pi %>% sin %>% cos
[1] 1
> cos(sin(pi))
[1] 1

For what it's worth, as of now (3 December 2021), in addition to the magrittr/tidyverse pipe (%>%), there also a native pipe |> in R (and an experimental => operator that can be enabled in the development version): see here, for example.

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • PS `do.call` might be redundant -- the body of the function could probably just be `f(x)`, although if you wanted to allow multiple arguments à la `list(1,5) %>% [back-quote]x[back-quote]` you would need `do.call` ... – Ben Bolker Jan 17 '12 at 16:26
10

Edit: package now on CRAN. Example included.

The magrittr package is made for this.

install.packages("magrittr")

Example:

iris %>%
  subset(Sepal.Length > 5) %>%
  aggregate(. ~ Species, ., mean)

Also, see the vignette:http://cran.r-project.org/web/packages/magrittr/vignettes/magrittr.html It has quite a few useful features if you like the F# pipe, and who doesn't?!

Stefan
  • 1,835
  • 13
  • 20
5

The problem is that you are talking about entirely different paradigms of calling functions so it's not really clear what you want. R only uses what in F# would be tuple arguments (named in R), so one way to think of it is trivially

fp = function(x, f) f(x)

which will perform the call so for example

> fp(4, print)
[1] 4

This is equivalent, but won't work in non-tupple case like 4 |> f x y because there is no such thing in R. You could try to emulate the F# functional behavior, but it would be awkward:

fp = function(x, f, ...) function(...) f(x, ...)

That will be always functional and thus chaining will work so for example

> tri = function(x, y, z) paste(x,y,z)
> fp("foo", fp("mar", tri))("bar")
[1] "mar foo bar"

but since R doesn't convert incomplete calls into functions it's not really useful. Instead, R has much more flexible calling based on the tuple concept. Note that R uses a mixture of functional and imperative paradigm, it is not purely functional so it doesn't perform argument value matching etc.

Edit: since you changed the question in that you are interested in syntax and only a special case, just replace fp above with the infix notation:

`%>%` = function(x, f) f(x)
> 1:10 %>% range %>% mean
[1] 5.5

(Using Ben's operator ;))

Simon Urbanek
  • 13,842
  • 45
  • 45