Monday, December 10, 2012

Neat F#: Pipe Forward

Functional programming dates back to the 1950s, but from my perspective it seems to have been garnering more attention in the software engineering community recently.  I first got really interested in it last year at CodeMash when Ben Lee introduced me to a little bit of Erlang.  It was so fascinating that I decided I had to dive in deeper.  F# being a .NET language, it was the obvious choice.  So I bought an ebook of Programming F# and started writing a few little programs.

Along the way there have been a few things that completely blew my mind, or that I thought were just flat out neat.  You could (and should) learn about these things from much better sources, but I love to share!

So to kick it off, this first post will cover the first thing in F# that really truly blew my mind: the Pipe Forward operator.  You see it used in F# all the time, and what it allows you specify the last parameter's value first, thus writing your statements in a more logical order.

So for example, this:
let testInts = [1;2;3;4;5;]
let evenInts = List.filter (fun i -> i % 2 = 0) testInts
Can be re-written as this:
let testInts = [1;2;3;4;5;]
let evenInts = testInts |> List.filter (fun i -> i % 2 = 0)
This example is trivial of course, but where this really starts to shine is when you can effectively describe an entire program in one chain of function calls:
let oddPrimes = 
    |> filterOdds
    |> filterPrimes
Basically what's happening here is that the value on the left of the pipe forward operator is being passed as the last parameter to the function on the right. In the first example, List.filter takes two parameters. The first is a function, and the second is a list. You'll find that all the functions in F# modules are structured so that the parameter most likely to be passed down a chain like this is defined as the last parameter.

At first I didn't think this was mind blowing at all. It just looked like a simple compiler trick. But then I learned this isn't in the compiler at all. In fact, |> is just a single line F# function. It's definition is nothing more than:
let (|>) x f = f x

F# also has a pipe backward operator:
let evenInts = List.filter (fun i -> i % 2 = 0) <| testInts
And it is defined as:
let (<|) f x = f x
If you've followed along this far, I hope you are boggling your mind as to what possible purpose this could serve! I know I was. The answer comes from the fact that operators have higher precedence in F#. So the pipe backwards operator allows you to avoid wrapping an expression in parenthesis. For example:
let output = "the result is: %d" (2 + 2)
Those parenthesis are such a drag. So we can rewrite this without them as:
let output = "the result is: %d" <| 2 + 2

No comments:

Post a Comment