My last blog post was yet another introduction to Currying and Partial application. Now I want to put the focus more on the why part. Why do we want to have our functions in curryied form most of the time? This is the first part of a small blog post series and shows partial application in F# pipelines.
Using “Fluent interfaces” is a popular technique to write code in a more readable form. In languages like C# they also provide a way to create the code much faster. On every . we get IntelliSense and this gives us a “fluid” way of writing.
Let’s consider the following task: we want to compute the sum of the square roots of all odd numbers between 1 and 100. In C# we can use the LINQ method chaining approach in order to do something like this:
Now how does this look in F#? It’s basically the same. We replace every . with the |> operator and use the analogous Seq.* functions:
Oups! What happened here? The F# compiler noticed a type error. Math.Sqrt needs a float as input but we gave it an int. C# uses implicit casts between int and float so we didn’t noticed the problem there. Implicit casts are a little bit problematic, at least if you want to have proper type inference so F# doesn’t have this feature. No problem, we are programmers so let’s add the conversion manually:
Notice that float is a function from int to float and not a cast.
Now you might ask: how does this all relate to partial application? The answer is simple: In every pipeline step we use a higher-order function (Seq.*) and apply the first parameter with a lambda. The second parameter is given via the |> operator from the line above.
By applying our rule of thumb from the last post were are able to remove the x parameters:
Now let’s step back to C#. Keeping this knowledge in mind we try to apply the same rule in order to get rid of the x parameters:
Oups again! Now we see same error in C#. In this case it doesn’t know how to apply the implicit cast. As I said they are “problematic”, but we know how to fix this:
Tags: Currying, F#, partial application
[…] Why do we need partial application? – Part 1 of n – Fluent interfaces and piping […]
Pingback by Currying and uncurrying in C# and F# » Rash thoughts about .NET, C#, F# and Dynamics NAV. — Monday, 30. January 2012 um 17:04 Uhr
[…] Why do we need partial application? – Part 1 of n – Fluent interfaces and piping […]
Pingback by Why do we need partial application? – Part 2 of n – Simulating type classes in C# and F# » Rash thoughts about .NET, C#, F# and Dynamics NAV. — Tuesday, 31. January 2012 um 16:55 Uhr
I believe that because none of the functions are passed out of the scope of the expression that partial application (the creation of an actual curried fn) is not necessary – the compiler could convert the pipes at compile-time into a simple nested expression where all arguments are present.
E.g.:
Range(1,100) |> Where(IsOdd) |> Select(Math.Sqrt) |> Sum
into:
Sum( Select(Math.Sqrt, Where( IsOdd, Range(1,100))))
If partial-application actually happens here it really just seems like a missing compiler optimization.
Comment by Mchael Robin — Thursday, 23. February 2012 um 23:58 Uhr