15

Is there a way to write pipelined functions in R where the result of one function passes immediately into the next? I'm coming from F# and really appreciated this ability but have not found how to do it in R. It should be simple but I can't find how. In F# it would look something like this:

let complexFunction x =
     x |> square 
     |> add 5 
     |> toString

In this case the input would be squared, then have 5 added to it and then converted to a string. I'm wanting to be able to do something similar in R but don't know how. I've searched for how to do something like this but have not come across anything. I'm wanting this for importing data because I typically have to import it and then filter. Right now I do this in multiple steps and would really like to be able to do something the way you would in F# with pipelines.

Matthew Crews
  • 4,105
  • 7
  • 33
  • 57
  • 1
    I'm not quite clear on what you're asking for: `complexFunction <- function(x) { x <- x^2;x <- x+5; x <- as.character(x); return(x) }` – Brandon Bertelsen Nov 13 '12 at 00:52
  • 1
    Possible duplicate: http://stackoverflow.com/questions/7290947/data-manipulation-in-r-in-linq-style – Owen Nov 13 '12 at 05:25
  • possible duplicate of [how to implement F#'s forward pipe operator in R?](http://stackoverflow.com/questions/8896820/how-to-implement-fs-forward-pipe-operator-in-r) – Blue Magister Jan 05 '14 at 21:44

5 Answers5

8

Here is a functional programming approach using Reduce. It is in fact an example from ?Reduce

square <- function(x) x^2
add_5 <- function(x)  x+5
x <- 1:5
## Iterative function application:
Funcall <- function(f, ...) f(...)

Reduce(Funcall, list(as.character, add_5, square,x), right = TRUE)
## [1] "6"  "9"  "14" "21" "30"

Or even more simply using the functional package and Compose

This is nice as it will create the function for you

library(functional)
do_stuff <-   Compose(square,add_5,as.character )
do_stuff(1:5)
##  [1] "6"  "9"  "14" "21" "30"

I note that I would not consider either of these approaches idiomatically R ish (if that is even a phrase)

mnel
  • 113,303
  • 27
  • 265
  • 254
7

We can use Compose from the functional package to create our own binary operator that does something similar to what you want

# Define our helper functions
square <- function(x){x^2}
add5 <- function(x){x + 5}

# functional contains Compose
library(functional)

# Define our binary operator
"%|>%" <- Compose

# Create our complexFunction by 'piping' our functions
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6"  "9"  "14" "21" "30"


# previously had this until flodel pointed out
# that the above was sufficient
#"%|>%" <- function(fun1, fun2){ Compose(fun1, fun2) }

I guess we could technically do this without requiring the functional package - but it feels so right using Compose for this task.

"%|>%" <- function(fun1, fun2){
    function(x){fun2(fun1(x))}
}
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6"  "9"  "14" "21" "30"
Dason
  • 60,663
  • 9
  • 131
  • 148
  • Can we get rid of the two `%%` symbls in `%|>%` ? They look ugly and cumbersome. Or is there any pecularity for the %% in R? I can't find explanation in the documentation. – Nick May 14 '15 at 03:10
  • 1
    They're required. I don't know where it's mentioned in the documentation on how to go about defining these things but it's there somewhere. User defined binary infix operators will always have the form `%something%` – Dason May 14 '15 at 03:27
5

I think that you might just want to write a function to do the steps you desire.

complexFunction <- function(x) {
    as.character(x^2 + 5)
}

Then just call complexFunction(x).


Edit to show what R is doing internally (@mnel) -- The way R parses the and evaluates as.character(x^2 + 5) does what you want

You can use codetools to investigate what R to see how the values are being passed to eachother

flattenAssignment(quote(as.character(x^2+5)))
[[1]]
[[1]][[1]]
x

[[1]][[2]]
`*tmp*`^2

[[1]][[3]]
`*tmp*` + 5


[[2]]
[[2]][[1]]
`as.character<-`(`*tmp*`, value = `*tmpv*`)

[[2]][[2]]
`+<-`(`*tmp*`, 5, value = `*tmpv*`)

[[2]][[3]]
`^<-`(x, 2, value = `*tmpv*`)

Or you can get the Lisp style representation to see how it is parsed (and the results passed)

showTree(quote(as.character(x^2+5)))
(as.character (+ (^ x 2) 5))
mnel
  • 113,303
  • 27
  • 265
  • 254
3

Since this question was asked, the magrittr pipe has become enormously popular in R. So your example would be:

library (magrittr)

fx <- function (x) {
     x %>%
     `^` (2) %>%
     `+` (5)  %>%
     as.character ()
     }

Note that the backquote notation is because I'm literally using R's built-in functions and I need to specially quote them to use them in this manner. More normally-named functions (like exp or if I'd created a helper function add) wouldn't need backquotes and would appear more like your example.

Note also that %>% passes the incoming value as the first argument to the next function automatically, though you can change this. Note also that an R function returns the last value calculated so I don't need to return or assign the calculation in order to return it.

This is a lot like the nice special operators defined by other answers, but it uses a particular function that's widely used in R now.

Wayne
  • 933
  • 7
  • 11
  • 1
    magrittr also provides aliases for commonly used functions, allowing you to pipe `add` instead of quoting `+` in backticks. See `?magrittr::extract` for the full list. – Empiromancer Apr 13 '18 at 16:35
0

This works for R pretty similar in F#:

"%|>%" <- function(x, fun){
    if(is.function(x)) {
      function(...) fun(x(...))
    } else {
      fun(x)
    }
}
Kun Ren
  • 4,715
  • 3
  • 35
  • 50