Part Seven | Functional Programming Through Elixir: Higher-Order Functions

Beyond Passing Functions Around

In Part Six, we saw how the pipe operator turns nested function calls into readable pipelines. In Part Two, we learned that functions are values. You can pass them to Enum.map and Enum.filter to transform and select data.

Now we’ll go deeper. A higher-order function is a function that does at least one of these things:

  1. Takes a function as an argument (like Enum.map)
  2. Returns a function as its result

You’ve already used higher-order functions when calling Enum.map and Enum.filter. This post covers the most important one you haven’t seen yet, reduce, then gets into writing your own higher-order functions and composing functions together.

Read More

Part Six | Functional Programming Through Elixir: The Pipe Operator

Unreadable Nesting

In Part Five, we saw how recursion replaces loops. Now let’s look at a different readability problem: nested function calls.

Say you need to take a user’s input, trim whitespace, convert it to lowercase, and capitalize the first letter. In Elixir, without the pipe operator, you’d write:

String.capitalize(String.downcase(String.trim("  HELLO WORLD  ")))
# "Hello world"

You have to read this from the inside out. The first operation (trim) is buried in the middle, and the last operation (capitalize) is on the outside. The more steps you add, the worse it gets.

If you’re coming from OOP, you might be used to method chaining, which reads left to right:

# Python - method chaining
"  HELLO WORLD  ".strip().lower().capitalize()
# "Hello world"
// JavaScript - method chaining
"  HELLO WORLD  ".trim().toLowerCase()
// "hello world"
// (JavaScript doesn't have a direct capitalize method)

Method chaining reads nicely, but it only works because each method is attached to the object. In functional programming, functions aren’t bound to objects. They’re standalone. So how do we get the same readability?

Read More

Part Five | Functional Programming Through Elixir: Recursion Over Iteration

A Different Way to Loop

In Part Four, we learned how pattern matching enables elegant data handling. Now we’ll tackle another fundamental shift: in functional programming, you don’t use loops - you use recursion.

If you’re coming from an object-oriented background, loops are probably second nature. for, while, forEach - these are the tools you reach for when you need to process multiple items. But in Elixir, immutability means you can’t have traditional loop counters that increment. Instead, you use recursion: functions that call themselves.

Once you understand recursion, you’ll find it more expressive than loops. It naturally handles complex iteration patterns, and Elixir’s tail-call optimization makes it just as efficient as loops in other languages.

Read More

Part Four | Functional Programming Through Elixir: Pattern Matching

A Different Way to Work with Data

In Part Three, we learned about pure functions and side effects. Now we’ll tackle one of the most distinctive features of functional programming: pattern matching.

Pattern matching is Elixir’s superpower for working with data. It’s not just a fancy way to assign variables - it’s a fundamentally different approach to extracting, validating, and routing data through your program. Once you understand pattern matching, you’ll find conditionals, type checking, and data extraction in OOP languages feel unnecessarily verbose.

Read More

Part Three | Functional Programming Through Elixir: Pure Functions vs Side Effects

The Foundation of Predictable Code

In the first post, we explored immutability. In the second post, we saw how functions are values. Now we’ll tackle a concept that ties them together: pure functions.

Pure functions are the building blocks of functional programming. They’re predictable, testable, and easy to reason about. But real applications need side effects - saving to databases, making HTTP requests, printing to the console. The key is knowing how to write pure functions and where to isolate side effects.

Read More

Part Two | Functional Programming Through Elixir: Functions as First-Class Citizens

Functions Are Values

In the first post, we explored how immutability changes the way we think about data. Now we’ll tackle another fundamental shift: in functional programming, functions are values just like numbers, strings, or lists. You can pass them as arguments, return them from other functions, store them in variables, and put them in data structures.

If you’re coming from object-oriented programming, you’ve probably encountered this concept through callbacks, lambdas, or method references. But in OOP, these often feel like workarounds or special cases. In functional programming languages like Elixir, treating functions as first-class citizens is natural and central to how you write code.

Read More

Part One | Functional Programming Through Elixir: Immutability vs Mutable State

The Foundation of Functional Programming

If you’re coming from an object-oriented programming background, one of the most fundamental shifts in thinking when learning functional programming is immutability. In Elixir and other functional languages, data never changes once it’s created. This might sound limiting at first, but it’s actually a superpower that unlocks predictability, thread safety, and easier debugging.

This is the first post in a series exploring functional programming concepts through Elixir, aimed at developers transitioning from OOP paradigms.

Read More