In “typical” programming languages, you often have a structure called a for-loop. The idea is that you take some values and for each of the values you do something.
For example to sum up the values in an array, we can do
total_sum = 0
for value in [5, 10, 2] {
total_sum = total_sum + value
}
Now the sum is stored in the total_sum
variable
In functional programming, for-loops aren’t a really thing. Functional programming isn’t about saying “now do this in this specific way”. In functional programming you express what needs to happen through functions who map a value to another value. All of this is a bit theoretical, though. The truth is that you still need to do things like listening for input, writing to output, storing things, etc. And it still uses the same underlying technology where a cpu will actually do the same kind of things like with another language. So in the end, it’s really just the same, we just express things slightly differently.
A for-loop is a way to handle an ordered list. In functional programming we will often use the reduce
function for that. And when you look at it closely enough, you may find that this reduce
function is really a for-loop in disguise.
reduce(enum, acc, fun)
Is equivalent to
for value in enum {
acc = fun(acc, value)
}
Here enum
stands for “enumerable”, acc
stands for “accumulator”, and fun
stands for “function” and also for how fun functional programming can be.
Let’s take a closer look using our previous example. We start with this
total_sum = 0
for value in [5, 10, 2] {
total_sum = total_sum + value
}
Everything between the brackets of the for-loop can be considered a function who takes the accumulator, in this case total_sum
, and the current value, in this case value
, and maps this to a new value for the accumulator. Our accumulator is the total_sum
variable, and the enumerable is obviously our array [5, 10, 2]
.
Written a bit differently, we get
enum = [5, 10, 2]
acc = 0
fun = (acc, value) => { return acc + value }
for value in enum {
acc = fun(acc, value)
}
And thus we can replace the for-loop with the reduce
function
enum = [5, 10, 2]
total_sum = reduce(enum, 0, (acc, value) => {
return acc + value
})
Neat, huh.
Here we “reduce” the numbers in the list to one number, but that’s not the only thing we can do. We can also create a new list based on the values of our original list. You can map each value to a possibly different value in the new list. Or create a list with certain values filtered out. In functional programming, languages have often implemented filter
and map
functions for that, but they are really just reduce
functions underneath.
Let’s filter odd numbers
filtered_list = []
for value in [5, 10, 2] {
if is_odd(value) {
filtered_list = filtered_list + [value]
}
}
This can be written with reduce
enum = [5, 10, 2]
filtered_list = reduce(enum, [], (acc, value) => {
if is_odd(value) {
return acc + [value]
}
return acc
})
Or shorter with a filter
function
enum = [5, 10, 2]
filtered_list = filter(enum, is_odd)
Or maybe we want to map the values to a list but with the values multiplied by two
multiplied_values = []
for value in [5, 10, 2] {
multiplied_values = multiplied_values + [value * 2]
}
which eventually can be written with a map
function as
enum = [5, 10, 2]
multiplied_values = map(enum, (value) => { return value * 2 })
And if you first want to filter out the odd numbers, and then map the result to multiples of two, you can easily do that in two steps
enum = [5, 10, 2]
filtered_list = filter(enum, is_odd)
filtered_multiplied_values = map(filtered_list, (value) => { return value * 2 })
Making it nicely short and easy.
Most languages will even allow you to “chain” things. For example, Elixir has the |>
operator allowing you to chain functions with the output of the previous function becoming the first input of the second function. Using such an operator we could get
filtered_multiplied_values =
[5, 10, 2]
|> filter(is_odd)
|> map((value) => { return value * 2 })
These days, non-functional languages, will often implement these functions as a method of Arrays or other enumerables.
filtered_multiplied_values = [5, 10, 2].filter(is_odd).map((value) => { return value * 2 })
Allowing you to write very compact, but also very expressive and readable, code.
Comments
September 18, 2024 09:42
The reduce function is a higher-order function that iterates over a sequence of elements (like a list or array) and combines them into a single fnf result using a specified binary operation. It essentially “reduces” a collection of values to a single value.