Day 2 of Learning Haskell: Comparisons with C++

Leonardo
3 min readMay 28, 2024

In my journey to learn Haskell and functional programming, I find it insightful to compare it directly with C++, a language I’m well-acquainted with. Today, I focused on how each language handles common programming tasks such as mapping, filtering, and reducing collections.

Function Composition and Mapping

First, let’s look at how each language performs function composition and mapping:

C++

Here’s how you might add 10 to each element in an array and then square the result in C++:

#include <iostream>
#include <vector>

using namespace std;

int f(int x) { return x + 10; }
int g(int x) { return x * x; };

int main() {
vector<int> xs{1, 2, 3};
vector<int> ys;

for (auto x : xs) {
ys.emplace_back(g(f(x)));
}

for (auto y : ys) {
cout << y << endl;
}
}

This example manually iterates over elements, applying the functions f and g. It’s clear and straightforward but involves explicit loop and storage management. It should output “121, 144, 169”.

Haskell

Function composition is a core concept in Haskell. Using the (.) operator, functions can be composed elegantly:

f x = x + 10

g x = x * x

main = print $ map (g . f) [1, 2, 3]

The composition g . f and map make this operation concise and expressive, focusing on what transformations to apply rather than how to apply them.

Filtering Elements

Next, let’s explore how to filter elements that meet a specific condition:

C++

To filter elements greater than 3 from a list:

#include <iostream>
#include <vector>

using namespace std;

int main() {
vector<int> xs{1, 2, 3, 4, 5, 6};
vector<int> ys;

for (auto x : xs) {
if (x > 3)
ys.emplace_back(x);
}

for (auto y : ys) {
cout << y << endl;
}
}

This approach again requires explicit iteration and condition checking. The output should be “[4, 5, 6]”.

Haskell

Haskell uses filter, a built-in function, to achieve the same goal with less code:

main = print $ filter (> 3) [1, 2, 3, 4, 5, 6]

This example is more readable and directly expresses the filtering criterion without the boilerplate of loops and conditionals.

Reduction Operations

Lastly, we look at reducing a list to a single value:

C++

To sum elements starting with an initial value:

#include <iostream>
#include <vector>

using namespace std;

int main() {
vector<int> xs{1, 2, 3};
int total = 1;

for (auto x : xs) {
total += x;
}

cout << total << endl;
}

The loop accumulates the sum of the elements, clearly showing each step of the computation.

Haskell

Haskell handles this with foldr, which is more abstract:

main = print $ foldr (+) 1 [1, 2, 3]

foldr elegantly collapses the list into a single value, with the function and initial value clearly specified.

Reflections on Day 2

Today’s comparison highlighted the elegance and brevity of Haskell’s functional programming style versus the explicit control offered by C++. While C++ requires detailed management of computation steps, Haskell abstracts these details, focusing instead on defining transformations in a high-level way.

The shift from thinking about “how” to “what” in Haskell is both challenging and rewarding, offering a fresh perspective on solving problems efficiently and expressively.

Continue following my Haskell learning journey on my GitHub at https://github.com/araujo88/haskell-tutorials.

I welcome your thoughts or experiences on transitioning between these programming paradigms or learning Haskell!

--

--

Leonardo

Software developer, former civil engineer. Musician. Free thinker. Writer.