Iris Classon
Iris Classon - In Love with Code

What purpose does the backward pipe serve in F#? (Q262)

When I first learned about the backwards pipe I was excited and immediately thought that it was rather cool. If you don’t know what a pipe is, it simply allows you to chain methods making the return value of one the input parameter of the next one. In F# it’s commonly seen as |> for forward piping, and <| for backwards piping. After getting over the ‘this is so cool’-feeling I realized I had no idea what to use it for. So in the air between Oslo and Stavanger (Norway) I decided to think about it a little bit and share what I know so far. F-sharpies might want to add to this post if you know some more, I’m a beginner in terms of F#.

reversePipeFSharp

The backwards pipe operator, <|, applies a function on the left of the operator to the value on the right of the operator.

Example:

let sum nrX nrY = nrX + nrY

// No parenthesis…yay! (?)

printfn “If we add we get…. %d” <| 2 + 3

// Oh noes.. parenthesis sad face

printfn “If we add we get…. %d” (2 + 3)

// Don’t get me started on double and triple reverse pipe operators

sum <|| (2,3)

In short, the only application I can find for the backwards pipe in F# is avoiding trailing parenthesis (but not always). Can this be true? This is it? I’m sure there must be more. Feel free to share if you know =)

Comments

Leave a comment below, or by email.
Ruben Bartelink
12/24/2013 2:44:37 AM
http://stackoverflow.com/a/5444278/11635 
Scott Wlaschin
12/24/2013 3:02:55 AM
I find it useful on those occasions when you have a chain of pipes, but for one of them you want to pass the data in as the FIRST param, rather than the last.

Here's an example:

// setup some functions
let replace (oldS:string) newS (a:string) = 
    a.Replace(oldS,newS)
let add a b = 
    sprintf "%s %s" a b
let toUpper (a:string) = 
    a.ToUpper()

// pipe "hello" through the functions
"hello" 
|> replace "h" "j"
|> add "world"  // "world is first param
|> toUpper

//result "WORLD JELLO" // not what we want

// pipe "hello" through the functions
"hello" 
|> replace "h" "j"
|> add  toUpper

//result "JELLO WORLD" // correct! 
Scott Wlaschin
12/24/2013 3:04:36 AM
Reply to: Scott Wlaschin
(again, with better formatting!)

// setup some functions
let replace (oldS:string) newS (a:string) = a.Replace(oldS,newS)
let add a b = sprintf "%s %s" a b
let toUpper (a:string) = a.ToUpper()

// pipe "hello" through the functions
"hello" 
|> replace "h" "j"
|> add "world"  // "world is first param
|> toUpper

//result "WORLD JELLO" // not what we want

// pipe "hello" through the functions
"hello" 
|> replace "h" "j"
|> add  toUpper

//result "JELLO WORLD" // correct! 
Scott Wlaschin
12/24/2013 3:08:01 AM
Reply to: Scott Wlaschin
The formatting is being stripped out!
The missing line in the second example should be:

(left pipe) add (right pipe) "world" 
Scott Wlaschin
12/24/2013 3:09:59 AM
Reply to: Scott Wlaschin
Here's the code in a gist 
https://gist.github.com/swlaschin/8111200 
MR
12/24/2013 3:40:00 AM
Yes backwards pipe is mostly used to avoid the closing paranthese. It's a bit like $ in haskell (explained here: http://learnyouahaskell.com/higher-order-functions#function-application)

Basically the reason is that one wants to lower the precendence of the function application operator.

When you type: 
printfn "%A" 1 + 2 

The F# compiler places the paranthesis like this due to precendence and left associativity of function application operator (http://msdn.microsoft.com/en-us/library/dd233228.aspx): 
(((printfn "%A") 1) + 2)

This won't compile which is why you have to either use parantheses or  (printfn "%A") (1 + 2)
printfn "%A"  (printfn "%A") <| (1 + 2)

The benefit of <| is mostly seen when the right-side expression spans several lines.


<| in F# isn't quite as good as $ in haskell though because . $ in haskell has the lowest precedence and is right associative which for this particular reason is what you want. Example of when <| fails us:
printfn "%A"  List.filter (fun x -> x%2 = 0)

(the problem is that  have the same precendence and associativity which makes the F# compiler place the parantheses "wrongly")

PS. The definition of backward pipe: let inline (  ) x f = f x
PS. Had to switch to Chrome to post here. Just FYI. 
MR
12/24/2013 3:41:50 AM
Reply to: MR
I notice the WP in it's wisdom are sometimes removing <| which breaks some of the code-samples. 
MR
12/24/2013 3:50:06 AM
Reply to: MR
Another place when <| shines is that F# warns when you call a function that returns a value you don't handle:
x.DoStuff ()

F# then asks you to either act on the value or ignore it:
ignore (x.DoStuff ())

I just prefer
ignore <| x.DoStuff ()

PS. This is something I wished for along time for C# so IMHO this warning is a good one 
Jesper Louis Andersen
12/24/2013 4:17:26 AM
The primary purpose of the operators |> and  for the "backward" variant, though I will use your naming style here, with |> being forward and  g |> h instead. This is nice since it also behaves better with newlines. You can line up the |> operators underneath each other and get a clearer view of what happens. Especially if g, say, is a composition of several other small functions.

In functional programming, it is common to have many small functions which are then composed to form the program. We need some tools to glue functions into compositions and this is where the >>, |> and  is glue for puzzle pieces that allows you to put them together in different ways.

The story of <| is almost the same. In code which is composition-heavy, you often have to read the code from right-to-left rather than left to right. In h(g(f(x))) the application of the inner function, f, happens first. Then g and finally h. So functional programmers often compose code in a right-to-left style. The backwards pipe is a bit more readable in this style: h <| g <| f x. And it follows the natural direction of the function call application.

<|| and <||| are just different variants for working with 2- and 3-tuples respectively. The pieces must fit together so things are type-correct. Hence their existence.

So the reason is mostly for giving the programmer different options for expressing their code to a reader. It is nice to be able to throw in either  to delimit other groups of code and make it easier to read. 
Jesper Louis Andersen
12/24/2013 4:20:44 AM
Oops, my less-thans got eaten by the blog software and made the description meaningless. Here is the full text:

https://gist.github.com/jlouis/8111923/raw/a453f1bd9efb054459142621e707949afeecbce3/gistfile1.txt 
MR
12/24/2013 4:34:15 AM
Reply to: MR
WRT to <|| and <||| I think the purpose of those is slightly different.

If you have a F# function taking two arguments and the values you have are in a tuple <|| can help.

You can do this:
let x,y = myTuple
let s = sum x y

or this:
let s = sum (fst myTuple) (sndmyTuple)

But with <|| you do this:
let s = sum <|| myTuple 
Per Persson
12/30/2013 10:07:50 AM
The operator <| in F# obviously corresponds to the operator $ in Haskell. That's defined by f $ x = f x, which by itself seems quite meaningless. But the associativity and precedence is set so that f $ g $ h $ x = f (g (h x)) and $ can thus be used to reduce the numbers of parenthesis. 
Rikard
4/11/2014 6:08:10 AM
Yes, it looks like those threading macros @Bodil were talking about at Oredev. In the right pipe you put stuff as first arg, and with left pipe as last arg. 


Last modified on 2013-12-23

comments powered by Disqus