A Software Engineering Blog

by Nick Holmes

  Home  |   Contact  |   Syndication    |   Login
  11 Posts | 0 Stories | 6 Comments | 0 Trackbacks

News

Archives

Post Categories

All this currying and partial application stuff is all very interesting, but surely its has to have some kind of run-time performance hit. What if I just want to keep things straightforward?

Firstly, if we have a function that takes only a single argument, there is nothing to curry. It makes no sense to call a function with no arguments, so your only option is to make the exact call.

That in mind, we can do this:

let repeat(str, n) = ...

That syntax is sure to catch out C# programmers (like me), because it looks a lot like a normal C# function call. You might not even register, at first glance, the extra parenthesis around the arguments. However, these parenthesis are nothing to do with the function syntax, but everything to do with tuples:

let name = ("Fred", "Smith")

here, name is equal to the pair of values “Fred” and “Smith”. Tuples can have more than 2 components. The type is reported as:

val x : string * string

Personally, I find that * as the separator a bit jarring, but I assume there is a good reason to use it in preference to “,” - maybe it will come to light some day.

Anyway, a tuple is a simple data structure that allows you to group 2 or more components into a single argument, and thereby create functions that need not be curried.

  • Share This Post:
  • Share on Twitter
  • Share on Facebook
  • Share on Technorati
posted on Tuesday, May 05, 2009 11:33 AM

Feedback

# re: Do I have to have a curried function in F#? 5/11/2009 6:25 PM Stephan
As far as I can see there's only one place where the curried default representation of functions introduces a runtime overhead for uncurried functions: When a function *closure* with more than argument is called, a dynamic type check needs to be performed before the uncurried representation can be called. Have a look at the Microsoft.FSharp.Core.FastFunc.InvokeFast members to see how this is done internally. You can use the OptimizedClosures.FastFunc classes to avoid this overhead for repeated calls to the same closure, see e.g. the implementation of List.fold_left.

Note that most calls in normal applications are calls to statically resolved functions or object methods, where there's no overhead. Introducing tuples to avoid currying will usually hurt performance, unless the F# compiler "optimizes them away". In the case of class methods the "argument tuple" is always optimized away, so that you can read the '*' as a comma if you want.

I suppose the * notation has its roots in the mathematical notation for product spaces/sets.


# re: Do I have to have a curried function in F#? 5/12/2009 5:23 PM Matthew Podwysocki
Nick,

The answer to your question is yes, of course partial application is needed. Take for example a pipelining of a map, then a filter, then a reduce of some sort. To have a partially applied solution is quite elegant such as the following:

let flip f y x = f x y
[1..10]
|> List.map (flip pown 2)
|> List.filter (flip (%) 3 >> (=) 0)
|> List.sum

Imagine if we had not partially applied this function at all, and instead as you suggested, keeping things in line with the C# approach, it might look like the following:

List.sum (List.filter (flip (%) 3 >> (=) 0) (List.map (flip pown 2) [1..10]))

The reason these concepts are important is that it creates much more readable code. I find it best to step into functional programming as a whole to really learn and understand these concepts and they'll become a bit more clear to you.

But to tuple the arguments of a given function? That's really not necessary and does make partial application much harder. Instead, learn the basic concepts and forget what you know about OOP. It's easier that way.

Matt

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: