Basics of functions
Most functions in F# are created with the
This defines a function named
timesTwo that takes a single parameter
x. If you run an interactive F# session (
fsharpi on OS X and Linux,
fsi.exe on Windows) and paste that function in (and add the
;; that tells
fsharpi to evaluate the code you just typed), you'll see that it replies with:
This means that
timesTwo is a function that takes a single parameter
x of type
int, and returns an
int. Function signatures are often written without the parameter names, so you'll often see this function type written as
int -> int.
But wait! How did F# know that
x was an integer parameter, since you never specified its type? That's due to type inference. Because in the function body, you multiplied
2, the types of
2 must be the same. (As a general rule, F# will not implicitly cast values to different types; you must explicitly specify any typecasts you want).
If you want to create a function that doesn't take any parameters, this is the wrong way to do it:
The right way to do it is:
hello function has the type
unit -> unit, which is explained in The "unit" type.
Curried vs Tupled Functions
There are two ways to define functions with multiple parameters in F#, Curried functions and Tupled functions.
All functions defined from outside F# (such as the .NET framework) are used in F# with the Tupled form. Most functions in F# core modules are used with Curried form.
The Curried form is considered idiomatic F#, because it allows for partial application. Neither of the following two examples are possible with the Tupled form.
The reason behind that is that the Curried function, when called with one parameter, returns a function. Welcome to functional programming !!
You can see it is exactly the same signature.
However, when interfacing with other .NET code, as in when writing libraries, it is important to define functions using the Tupled form.
Functions of more than one parameter
In F#, all functions take exactly one parameter. This seems an odd statement, since it's trivially easy to declare more than one parameter in a function declaration:
But if you type that function declaration into the F# interactive interpreter, you'll see that its type signature is:
Without the parameter names, that signature is
int -> int -> int. The
-> operator is right-associative, which means that this signature is equivalent to
int -> (int -> int). In other words,
add is a function that takes one
int parameter, and returns a function that takes one
int and returns
int. Try it:
However, you can also call a function like
add in a more "conventional" manner, directly passing it two parameters, and it will work like you'd expect:
This applies to functions with as many parameters as you want:
This method of thinking about multi-parameter functions as being functions that take one parameter and return new functions (which may in turn take one parameter and return new functions, until you reach the final function that takes the final parameter and finally returns a result) is called currying, in honor of mathematician Haskell Curry, who is famous for developing the concept. (It was invented by someone else, but Curry deservedly gets most of the credit for it.)
This concept is used throughout F#, and you'll want to be familiar with it.
Inlining allows you to replace a call to a function with the body of the function.
This is sometimes useful for performance reason on critical part of the code. But the counterpart is that your assembly will takes much space since the body of the function is duplicated everywhere a call occurred. You have to be careful when deciding whether to inline a function or not.
A function can be inlined with the
Another example with local value:
Pipe Forward and Backward
Pipe operators are used to pass parameters to a function in a simple and elegant way. It allows to eliminate intermediate values and make function calls easier to read.
In F#, there are two pipe operators:
|>): Passing parameters from left to right
<|): Passing parameters from right to left
Here is an example without pipe operators:
We can shorten the previous example and make it cleaner with the forward pipe operator:
Each function result is passed as a parameter to the next function.
If you want to pass multiple parameters to the pipe operator, you have to add a
| for each additional parameter and create a Tuple with the parameters. Native F# pipe operator supports up to three parameters (|||> or <|||).