# F Sharp Programming/Values and Functions

F# : Declaring Values and Functions |

Compared to other .NET languages such as C# and VB.Net, F# has a somewhat terse and minimalistic syntax. To follow along in this tutorial, open F# Interactive (fsi) or Visual Studio and run the examples.

## Contents

## Declaring Variables[edit]

The most ubiquitous, familiar keyword in F# is the `let`

keyword, which allows programmers to declare functions and variables in their applications.

For example:

let x = 5

This declares a variable called `x`

and assigns it the value `5`

. Naturally, we can write the following:

let x = 5 let y = 10 let z = x + y

`z`

now holds the value 15.

A complete program looks like this:

let x = 5 let y = 10 let z = x + y printfn "x: %i" x printfn "y: %i" y printfn "z: %i" z

The statement `printfn`

prints text out to the console window. As you might have guessed, the code above prints out the values of `x`

, `y`

, and `z`

. This program results in the following:

x: 5 y: 10 z: 15

Note to F# Interactive users: all statements in F# Interactive are terminated by

`;;`

(two semicolons). To run the program above in fsi, copy and paste the text above into the fsi window, type`;;`

, then hit enter.

### Values, Not Variables[edit]

In F#, "variable" is a misnomer. In reality, all "variables" in F# are immutable; in other words, once you bind a "variable" to a value, it's stuck with that value forever. For that reason, most F# programmers prefer to use "value" rather than "variable" to describe `x`

, `y`

, and `z`

above. Behind the scenes, F# actually compiles the "variables" above as static read-only properties.

## Declaring Functions[edit]

There is little distinction between functions and values in F#. You use the same syntax to write a function as you use to declare a value:

let add x y = x + y

`add`

is the name of the function, and it takes two parameters, `x`

and `y`

. Notice that each distinct argument in the functional declaration is separated by a space. Similarly, when you execute this function, successive arguments are separated by a space:

let z = add 5 10

This assigns `z`

the return value of this function, which in this case happens to be `15`

.

Naturally, we can pass the return value of functions directly into other functions, for example:

let add x y = x + y let sub x y = x - y let printThreeNumbers num1 num2 num3 = printfn "num1: %i" num1 printfn "num2: %i" num2 printfn "num3: %i" num3 printThreeNumbers 5 (add 10 7) (sub 20 8)

This program outputs:

num1: 5 num2: 17 num3: 12

Notice that I have to surround the calls to `add`

and `sub`

functions with parentheses; this tells F# to treat the value in parentheses as a single argument.

Otherwise, if we wrote `printThreeNumbers 5 add 10 7 sub 20 8`

, its not only incredibly difficult to read, but it actually passes 7 parameters to the function, which is obviously incorrect.

### Function Return Values[edit]

Unlike many other languages, F# functions do not have an explicit keyword to return a value. Instead, the return value of a function is simply the value of the last statement executed in the function. For example:

let sign num = if num > 0 then "positive" elif num < 0 then "negative" else "zero"

This function takes an integer parameter and returns a string. As you can imagine, the F# function above is equivalent to the following C# code:

string Sign(int num) { if (num > 0) return "positive"; else if (num < 0) return "negative"; else return "zero"; }

Just like C#, F# is a strongly typed language. A function can only return one datatype; for example, the following F# code will not compile:

let sign num = if num > 0 then "positive" elif num < 0 then "negative" else 0

If you run this code in fsi, you get the following error message:

> let sign num = if num > 0 then "positive" elif num < 0 then "negative" else 0;; else 0;; ---------^

stdin(7,10): error FS0001: This expression was expected to have type string but here has type int

The error message is quite explicit: F# has determined that this function returns a `string`

, but the last line of the function returns an `int`

, which is an error.

Interestingly, *every* function in F# has a return value; of course, programmers don't always write functions that return useful values. F# has a special datatype called `unit`

, which has just one possible value: `()`

. Functions return `unit`

when they don't need to return any value to the programmer. For example, a function that prints a string to the console obviously doesn't have a return value:

let helloWorld = printfn "hello world"

This function takes no parameters and returns `()`

. You can think of `unit`

as the equivalent to `void`

in C-style languages.

### How To Read Arrow Notation[edit]

All functions and values in F# have a data type. Open F# Interactive and type the following:

> let addAndMakeString x y = (x + y).ToString();;

F# reports the data type using chained arrow notation as follows:

val addAndMakeString : x:int -> y:int -> string

Data types are read from left to right. Before muddying the waters with a more accurate description of how F# functions are built, consider the basic concept of Arrow Notation: starting from the left, our function takes two `int`

inputs and returns a `string`

. A function only has one return type, which is represented by the rightmost data type in chained arrow notation.

We can read the following data types as follows:

**int -> string**

- takes one
`int`

input, returns a`string`

**float -> float -> float**

- takes two
`float`

inputs, returns another`float`

**int -> string -> float**

- takes an
`int`

and a`string`

input, returns a`float`

This description is a good introductory way to understand Arrow Notation for a beginner--and if you are new to F# feel free to stop here until you get your feet wet. For those who feel comfortable with this concept as described, the actual way in which F# is implementing these calls is via **currying** the function.

### Partial Function Application[edit]

While the above description of Arrow Notation is intuitive, it is not entirely accurate due to the fact that **F# implicitly curries functions**. This means that a function only ever has a single argument and a single return type, quite at odds with the previous description of Arrow Notation above where in the second and third example two arguments are passed to a function. In reality, a function in F# **only ever** has a single argument and a single return type. How can this be? Consider this type:

**float -> float -> float**

since a function of this type is implicitly curried by F#, there is a two step process to resolve the function when called with two arguments

- a function is called with the first argument that
**returns a function**that takes a float and returns a float. To help clarify currying, lets call this function**funX**(note that this naming is just for illustration purposes--the function that gets created by the runtime is anonymous). - the second function ('
**funX**' from step 1 above) is called with the second argument, returning a float

So, if you provide two floats, the result appears as if the function takes two arguments, though this is not actually how the runtime behaves. The concept of currying will probably strike a developer not steeped in functional concepts as very strange and non-intuitive--even needlessly redundant and inefficient, so before attempting a further explanation, consider *the benefits of curried functions* via an example:

let addTwoNumbers x y = x + y

this type has the signature of

**int -> int -> int**

then this function:

let add5ToNumber = addTwoNumbers 5

with the type signature of

. Note that the body of **(int -> int)**`add5ToNumber`

calls `addTwoNumbers`

with only one argument--not two. It **returns a function** that takes an int and returns an int. In other words, `add5toNumber`

**partially applies** the `addTwoNumbers`

function.

> let z = add5ToNumber 6;; val z : int = 11

This partial application of a function with multiple argument exemplifies the power of curried functions. It allows **deferred application** of the function, allowing for more modular development and code re-use--we can re-use the `addTwoNumbers`

function to create a new function via partial application. From this, you can glean the power of function currying: it is always breaking down function application to the smallest possible elements, facilitating greater chances for code-reuse and modularity.

Take another example, illustrating the use of partially applied functions as a bookkeeping technique. Note the type signature of `holdOn`

is a function (int -> int) since it is the partial application of `addTwoNumbers`

> let holdOn = addTwoNumbers 7;; val holdOn : (int -> int) > let okDone = holdOn 8;; val okDone : int = 15

Here we define a new function `holdOn`

on the fly just to keep track of the first value to add. Then later we apply this new 'temp' function `holdOn`

with another value which returns an int. Partially applied functions--enabled by currying--is a very powerful means of controlling complexity in F#. In short, the reason for the indirection resulting from currying function calls affords partial function application and all the benefits it supplies. In other words, the goal of partial function application is enabled by implicit currying.

So while the Arrow Notation is a good shorthand for understanding the type signature of a function, it does so at the price of oversimplification, for a function with the type signature of

f : int -> int -> int

is actually (when taking into consideration the implicit currying):

// curried version pseudo-code f: int -> (int -> int)

In other words, f is a function that takes an int and returns a function that takes an int and returns an int. Moreover,

f: int -> int -> int -> int

is a simplified shorthand for

// curried version pseudo-code f: int -> (int -> (int -> int))

or, in very difficult to decode English: f is a function that takes an int and returns a function that takes an int that returns a function that takes an int and returns an int. Yikes!

### Nested Functions[edit]

F# allows programmers to nest functions inside other functions. Nested functions have a number of applications, such as hiding the complexity of inner loops:

let sumOfDivisors n = let rec loop current max acc = if current > max then acc else if n % current = 0 then loop (current + 1) max (acc + current) else loop (current + 1) max acc let start = 2 let max = n / 2 (* largest factor, apart from n, cannot be > n / 2 *) let minSum = 1 + n (* 1 and n are already factors of n *) loop start max minSum printfn "%d" (sumOfDivisors 10) (* prints 18, because the sum of 10's divisors is 1 + 2 + 5 + 10 = 18 *)

The outer function `sumOfDivisors`

makes a call to the inner function `loop`

. Programmers can have an arbitrary level of nested functions as need requires.

### Generic Functions[edit]

In programming, a generic function is a function that returns an indeterminate type `t`

without sacrificing type safety. A generic type is different from a concrete type such as an `int`

or a `string`

; a generic type represents a *type to be specified later*. Generic functions are useful because they can be generalized over many different types.

Let's examine the following function:

let giveMeAThree x = 3

F# derives type information of variables from the way variables are used in an application, but F# can't constrain the value `x`

to any particular concrete type, so F# generalizes `x`

to the generic type `'a`

:

`'a -> int`

- this function takes a generic type
`'a`

and returns an`int`

.

When you call a generic function, the compiler substitutes a function's generic type's with the data types of the values passed to the function. As a demonstration, let's use the following function:

let throwAwayFirstInput x y = y

Which has the type `'a -> 'b -> 'b`

, meaning that the function takes a generic `'a`

and a generic `'b`

and returns a `'b`

.

Here are some sample inputs and outputs in F# interactive:

> let throwAwayFirstInput x y = y;; val throwAwayFirstInput : 'a -> 'b -> 'b > throwAwayFirstInput 5 "value";; val it : string = "value" > throwAwayFirstInput "thrownAway" 10.0;; val it : float = 10.0 > throwAwayFirstInput 5 30;; val it : int = 30

`throwAwayFirstInput 5 "value"`

calls the function with an `int`

and a `string`

, which substitutes `int`

for `'a`

and `string`

for `'b`

. This changes the data type of `throwAwayFirstInput`

to `int -> string -> string`

.

`throwAwayFirstInput "thrownAway" 10.0`

calls the function with a `string`

and a `float`

, so the function's data type changes to `string -> float -> float`

.

`throwAwayFirstInput 5 30`

just happens to call the function with two `int`

s, so the function's data type is incidentally `int -> int -> int`

.

Generic functions are strongly typed. For example:

let throwAwayFirstInput x y = y let add x y = x + y let z = add 10 (throwAwayFirstInput "this is a string" 5)

The generic function `throwAwayFirstInput`

is defined again, then the `add`

function is defined and it has the type `int -> int -> int`

, meaning that this function must be called with two `int`

parameters.

Then `throwAwayFirstInput`

is called, as a parameter to `add`

, with two parameters on itself, the first one of type string and the second of type int. This call to `throwAwayFirstInput`

ends up having the type `string -> int -> int`

. Since this function has the return type `int`

, the code works as expected:

> add 10 (throwAwayFirstInput "this is a string" 5);; val it : int = 15

However, we get an error when we reverse the order of the parameters to `throwAwayFirstInput`

:

> add 10 (throwAwayFirstInput 5 "this is a string");; add 10 (throwAwayFirstInput 5 "this is a string");; ------------------------------^^^^^^^^^^^^^^^^^^^ stdin(13,31): error FS0001: This expression has type string but is here used with type int.

The error message is very explicit: The `add`

function takes two `int`

parameters, but `throwAwayFirstInput 5 "this is a string"`

has the return type `string`

, so we have a type mismatch.

Later chapters will demonstrate how to use generics in creative and interesting ways.