Fortran - Functional Programming Concepts - Reduce
We’ve implemented filter and map operations. The results of both these operations are new arrays. Yet another common operation on arrays is the so-called reduction operation; we “reduce” multiple values to a single value. The most obvious example is calculating the sum of an array of integers: the input is an array (or list) and the output is a single integer
:
pure function sum_all(numbers) result(res)
integer, dimension(:), intent(in) :: numbers
integer :: res
integer :: i
res = 0
do i = 1, size(numbers)
res = res + numbers(i)
end do
end function sum_all
Just like with filter
and map
we can imagine a generalization of this process, which involves looping over the array elements and building up a single return value along the way. We start with the existing sum_all
function. The first step is to let the user decide what the return value should be, which is the logic that happens inside the do
loop. We extract a function for this:
By Matthias Noback
read moreFortran - Functional Programming - List type
In the previous post we looked at this dream scenario:
list([1, 3, 5, 7]) % filter(divisible_by(3)) % map(square)
As mentioned, we can’t chain function calls like this. But we can put intermediate results in local variables and achieve something similar:
integers = list([1, 3, 5, 7])
divisible_by_3 = integers%filter(divisible_by(3))
squared = divisible_by_3%map(square)
If the intermediate values are all the same type, we can reuse the variable:
integers = list([1, 3, 5, 7])
integers = integers%filter(divisible_by(3))
integers = divisible_by_3%map(square)
To enable this syntax, it’s clear that we need to introduce a derived type for a list of integers that has type-bound procedures filter
and map
. These functions should each return a new list, so we can call any of these functions again on the new list. Let’s start with an integer_list_t
which contains an array of integers. We also provide a generic list
interface
with a specific procedure create_integer_list
for creating the integer_list_t
:
By Matthias Noback
read moreFortran - Functional Programming Concepts - Map
We considered the problem of filtering elements in an array, keeping only the ones we want. A decision about that is made by a function we pass as an argument.
A similar problem, but with its own challenges, is when we have an array of values and want to create a new array, with an equal number of elements, but each element has been transformed in some way. For instance, say we have an array of integers and want to square each integer. A procedural approach looks as follows:
By Matthias Noback
read moreFortran - Functional Programming Concepts - Closures
We have a reusable filter
function to which we pass the name of a procedure that matches a given interface
. But can we also do something like this?
filter([1, 2, 3, 4], is_divisible_by(3))
Closures
This is a very common thing in functional programming. It involves something called higher-order functions. This means that a function may itself return a function. In this case, is_divisible_by
returns a function that can be passed to filter
. This returned function also needs to remember the value 3 that was passed to it. When it’s executed for each value in the integer array, it will check if that value is divisible by 3. In other languages such a function is called a closure; it’s a function that can be passed around as a value. Besides the function itself, it also has the data from the context where it was created - “bound” to it. In “ideal Fortran”, we would write something like this:
By Matthias Noback
read more