This article will be a hands-on guide to understanding F# functions and patterns, as well as higher-order functions in F#.
We will also explore how F# simplifies the process of composing functions so that complex behaviors can be created. You will gain a solid understanding of how to use F# functions, regardless of whether you’re new to the language or an experienced programmer.
The fundamental building blocks of any F# programs are functions which form the basis for the program.
F# allows functions to behave as first-class citizens by giving them the ability to be passed as arguments, used as values, and returned as results using the built-in class design. By doing this, you are able to write code in a highly expressive and concise manner.
There is a similarity between F# functions and data types. Using F# function is like declaring a variable like any other variable.
You can use functions just as you can use other variables, which means that you can:
- Describe the function by assigning a name and an associated type to that function.
- Add a value.
- On the basis of that value, perform some calculations.
- A parameter can be passed from one function or subroutine to another.
- Taking the result of some other function and returning it as a function.
F# Function Creation
With the help of the let keyword, functions can be defined. The syntax of a function definition is as follows:
let [inline] function-name parameter-list [ : return-type ] = function-body
- F# Function-name refers to the identifier for the function in the program.
- Parameter-list allows you to specify a list of parameters separated by spaces. If you do not specify any explicit type for a parameter, the compiler will deduce the type based on the body of the function (the same as it does with variables).
- A function body is a combination of several expressions or a compound expression, which is built up from several expressions. The last expression is the return value of the function in the function body.
- Return-type is an optional field that consists of a colon followed by a type. In the case of a function with no return type specified, the compiler will try to determine it from the final expression in the body of the function.
F# Function Parameters
The parameters of a F# functions are used to pass values into the function that it can operate upon. According to the particular problem being solved, the types and numbers of parameters needed by a function differ depending on the nature of the problem.
There is no limit to the number of parameters defined within a function, and they are declared after the name of the function, separated by colons.
The parameters are treated as variables within the function, and are able to be used for calculations or for making decisions based on them.
As soon as the function is called, the parameter values are passed to it in parentheses with a space between them. There must be a match between the order of the values and the order of the parameters in the definition of the function. When writing functional code in F#, it is important to understand how parameters work and manipulate them.
A parameter can be specified according to its type. The compiler infers the parameter type if no type is specified.
As an example,
let rectangle(l : int, w: int) = l * w
Calling a Function
In order to call a function, it is necessary to specify the name of the function followed by a space and then the argument values separated by spaces.
As an example,
let rect = rectangle 3 4,
Below are some examples of how these concepts can be demonstrated using the following programs.
The following example calculates the area of a square using the Fsharp functions:
Area of Rectangular is: 24
There are two parameters in the following program that must be used to return the largest value:
Above example defines a function max in F# that takes two integer parameters num1 and num2 and returns the maximum value of the two numbers. The function returns int32.
The function body contains an if statement that checks whether num1 is greater than num2. If num1 is greater than num2, then the function returns num1. Otherwise, it returns num2.
After defining the max function, the code calls it with arguments 14 and 2 to find the largest value between the two. The result is assigned to the variable largest.
Finally, the printfn function is used to print a message that displays the value of largest.
Below is an another example of squaring the value of 12:
During the execution of a recursive function in F#, the function calls itself repeatedly. It is often helpful to use recursive functions in solving problems where it is possible to break them down into smaller sub-problems, and then recursively solve those smaller sub-problems.
By using the let recursive keyword combination, you are able to define a recursive method.
Recursive functions are defined by the following syntax:
//Recursive function definition let rec function-name parameter-list = recursive-function-body
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
This is an example of how you can calculate the factorial of a number by using recursive functions in F#:
Following is an output of the above example:
Factorial of 5 is: 120
The following example prints the sum of n numbers by adding 1 extra using a recursive function:
The output of the above example is as follows:
The sum of first 8 integers is: 37
Here is a program that returns Fibonacci numbers from 1 to 5 by using recursive function:
After execution of the program the example above prints the following result:
Fibonacci series on 1 is: 1 Fibonacci series on 2 is: 1 Fibonacci series on 3 is: 2 Fibonacci series on 4 is: 3 Fibonacci series on 5 is: 5
Above example defines a recursive function fib in F# that computes the nth number in the Fibonacci sequence. The Fibonacci sequence is a series of numbers where each number is the sum of the previous two numbers. The first two numbers in the sequence are 0 and 1.
The fib function takes an integer parameter n and uses a recursive algorithm to compute the nth number in the Fibonacci sequence. If n is less than or equal to 1, the function returns n as a result. Otherwise, it recursively calls itself with n – 1 and n – 2 as arguments and returns the sum of the two results.
The second part of the code is a loop that prints the first 5 numbers in the Fibonacci sequence using the printfn function. It calls the fib function with i as the parameter to compute the ith number in the sequence and prints the result using a formatted string.
Arrow Notations in F#
F# provides data type information about functions and values, using chained arrow notation to report data types. Let’s take an example, in which we are going to take one int as input, and we are going to return a string as output. This can be written in arrow notation as follows:
int -> string
There is a left-to-right reading order for data types.
Taking another hypothetical function as an example, we can assume that it takes two integer inputs and returns a string.
let intToString x y = (x / y).ToString();
The data type in F# is represented by chained arrow notation as follows:
val intToString : x:int -> y:int -> string
The return type is determined by the type of data at the rightmost point of the chained arrow notation.
Here are a few more examples:
|float → float → float
|Taking two float inputs, the function returns another float based on the inputs.
|Int → String → float
|There is a function that takes an integer and a string input, and returns a float value.
When you use lambda expressions in F#, you create anonymous functions that will be placed directly into your code as values. The functions can either be passed as arguments to other functions or represented as data in functional programming.
First we create the function as a normal method:
Both examples work similarly and print the following output as follows:
The following is another example of how to print the sum of three values using lambda function:
Output of the above example is:
Sum is 60
F# Function Composition and Pipelining
The concept of function composition and pipelining is one of the common techniques used by functional programmers to combine functions into a more complex operation.
Pipelining is a method of passing a value through multiple functions to provide a final result.
Function composition involves chaining together multiple functions in order to produce a new function.
Code can be made more concise, modular, and readable and understandable using both techniques.
This example demonstrates how a function named f can be created from two functions named function 1 and function 2 by combining the values of these two functions into a single function.
After executing the example it prints out as follows:
Composition function result is: 10
There is also a special feature within F# that allows for the pipelining of functions. Using the pipelining method, functions can be chained together so that they can be executed sequentially.
Here is an example of how pipelining works:
The output of the above code is as follows:
Pipelining result is: 14
In this code, we first define two functions addTwo and double that take a single argument x and perform some mathematical operation on it.
Next, we use the |> operator, which is the forward pipe operator, to apply the functions addTwo and double to the value 5. The forward pipe operator takes the value on the left-hand side and passes it as the argument to the function on the right-hand side. So, 5 |> addTwo passes 5 as the argument to addTwo, which returns 7. Then, 7 |> double passes 7 as the argument to double, which returns 14.
Finally, we assign the result of the function composition to a variable called result. In this case, the result is 14. We then use printfn to print the value of the result to the console.
If you liked this article and found it informative regarding F# functional programming language, you can leave your feedback by reacting below.