R Pipelining functions

前端 未结 5 1991
北荒
北荒 2020-12-10 12:14

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 b

相关标签:
5条回答
  • 2020-12-10 12:32

    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))
    
    0 讨论(0)
  • 2020-12-10 12:40

    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)

    0 讨论(0)
  • 2020-12-10 12:49

    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.

    0 讨论(0)
  • 2020-12-10 12:50

    This works for R pretty similar in F#:

    "%|>%" <- function(x, fun){
        if(is.function(x)) {
          function(...) fun(x(...))
        } else {
          fun(x)
        }
    }
    
    0 讨论(0)
  • 2020-12-10 12:51

    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"
    
    0 讨论(0)
提交回复
热议问题