I have a piece of code:
links
|> Seq.map (fun x -> x.GetAttributeValue ("href", "no url"))
Which I wanted to rewrite to:
links
|> Seq.map (fun x -> (x.GetAttributeValue "href" "no url"))
But the F# compiler doesn't seem to like that. I was under the impression that these two function calls were interchangeable:
f (a, b)
(f a b)
The error that I get is:
The member or object constructor 'GetAttributeValue' taking 2 arguments are not accessible from this code location. All accessible versions of method 'GetAttributeValue' take 2 arguments.
Which seems amusing, as it seems to indicate that it needs what I'm giving it. What am I missing here?
A usual function call in F# is written without parentheses and parameters are separated by spaces. The simple way to define a function of several parameters is to write this:
As Pascal noted, this way of specifying parameters is called currying - the idea is that a function takes just a single parameter and the result is a function that takes the second parameter and returns the actual result (or another function). When calling a simple function like this one, you would write
add 10 5
and the compiler (in principle) interprets this as((add 10) 5)
. This has some nice advantages - for example it allows you to use partial function application where you specify only a first few arguments of a function:This feature is practically useful for example when processing lists:
Now, let's get to the confusing part - in F#, you can also work with tuples, which are simple data types that allow you to group multiple values into a single values (note that tuples aren't related to functions in any way). You can for example write:
When you write a function that takes parameters in parentheses separated by a comma, you're actually writing a function that takes a single parameter which is a tuple:
This is a function of a different type - it takes a single parameter which is a tuple, while the first version was a function that took two parameters (using currying).
In F#, the situation is a bit more complicated than that - .NET methods appear as methods that take a tuple as a parameter (so you can call them with the parenthesized notation), but they are somewhat limited (e.g. you cannot create a tuple first and then call the method giving it just the tuple). Also, the compiled F# code doesn't actually produce methods in the curried form (so you cannot use partial function application directly from C#). This is due to performance reasons - most of the times, you specify all arguments and this can be implemented more efficiently.
However, the principle is that a function either takes multiple parameters or takes a tuple as a parameter.
In
f (a,b)
,f
must be a function that takes a single argument (which is a pair).In
f a b
, which is short for(f a) b
,f
when applied toa
returns a function that is applied tob
.Both are almost equivalent ways to pass arguments to a function, but you cannot use a function designed for one style with the other. The second style is called "currying". It has the advantage of allowing some computations to be made as soon as
a
is passed, especially if you are going to use the samea
with differentb
s. In this case you can write:To answer your implicit question, in this kind of situation, it can be useful to write a little helper function:
and depending on how you want to use it, it might be more useful to curry it 'backwards':