Programming paradigms

One of the biggest hurdles to understanding functional programs when coming from an imperative background is the shift in thinking. Imperative programs describe how to do something, whereas declarative programs describe what to do. Let’s sum the numbers from 1 to 10 to show this.

Imperative

#![allow(unused)]
fn main() {
let mut sum = 0;
for i in 1..11 {
    sum += i;
}
println!("{sum}");
}

With imperative programs, we have to play compiler to see what is happening. Here, we start with a sum of 0. Next, we iterate through the range from 1 to 10. Each time through the loop, we add the corresponding value in the range. Then we print it out.

isum
11
23
36
410
515
621
728
836
945
1055

This is how most of us start out programming. We learn that a program is a set of steps.

Declarative

#![allow(unused)]
fn main() {
println!("{}", (1..11).fold(0, |a, b| a + b));
}

Whoa! This is really different! What’s going on here? Remember that with declarative programs we are describing what to do, rather than how to do it. fold is a function that composes functions. The name is a convention from Haskell.

Here, we are composing functions of addition (this closure: |a, b| a + b) with a range from 1 to 10. The 0 is the starting point, so a is 0 at first. b is the first element of the range, 1. 0 + 1 = 1 is the result. So now we fold again, with a = 1, b = 2 and so 1 + 2 = 3 is the next result. This process continues until we get to the last element in the range, 10.

abresult
011
123
336
6410
10515
15621
21728
28836
36945
451055
Last change: 2024-12-17, commit: cffcf31