Functional Programming Patterns for Elixir

What if learning was in scope?

A solid foundation built not just for use—but for understanding, mastery, and real growth.

Funx Banner

Installation

Add Funx to your mix.exs dependencies:

def deps do
  [
    {:funx, "~> 0.2.0"}
  ]
end

Then run: mix deps.get

Interactive Examples

Don't just read—practice. Use Livebooks to experiment, try patterns with live code, and check your understanding.

Launch Livebooks

Built for AI-Assisted Learning

Every module includes comprehensive usage rules designed specifically for LLMs. Your AI assistant can explain, not just suggest—keeping answers grounded in your code context.

Either DSL - Declarative Error Handling

Pipeline-friendly syntax for operations that can fail. Safe, ergonomic, and declarative.

The Problem

Elixir developers love pipelines, but traditional pipes break down with branching functions that return {:ok, value} or {:error, reason}.

The common solution—using bang functions (!)—sacrifices safety for ergonomics.

The Either DSL Solution

Get both safety and ergonomics. Write declarative pipelines that surface intent while handling errors gracefully.

Safe, ergonomic, and pipeline-friendly.

Before & After

Traditional (Unsafe)
# Might crash!
assignment = Ash.get!(Assignment, id)
case close_assignment(assignment) do
  {:ok, updated} ->
    Ash.load!(updated, [:status])
  {:error, error} ->
    {:error, error}
end
Either DSL (Safe & Ergonomic)
use Funx.Monad.Either

either Assignment, as: :tuple do
  bind Ash.get(id)
  bind close_assignment()
  bind Ash.load([:status])
end

Key Features

Declarative Pipelines

Write error-handling code that surfaces intent, not implementation details.

Automatic Lifting

Handles plain values, result tuples, and Either values automatically.

Fail-Fast by Default

Short-circuits on the first error, no unnecessary computation.

Flexible Returns

Choose Either, tuple, or raise formats with as: option.

Compile-Time Safety

Warns when using bind vs map incorrectly.

Kleisli Composition

Chain operations that return branching types naturally.

Available Operations

bind

Chain operations that can fail (return Either or result tuples)

map

Transform values with functions that always succeed

ap

Apply functions wrapped in Either to values wrapped in Either

validate

Collect all validation errors from multiple validators

Plus

Either functions: filter_or_else, or_else, map_left, flip

"Surface intent over implementation—focus on what your code does, not how the machinery works."

Core Patterns

These modules are ordered so each builds on the last. Start with Eq/Ord, then move through monoids, predicates, and monads.

Equality & Ordering

Eq Protocol

Define what "equal" means for your domain:

  • • Compare by ID, name, or any attribute
  • • Compose multiple comparisons
  • • Works with structs and built-in types

Ord Protocol

Structured ordering without built-in operators:

  • • Order by size, age, or priority
  • • Chain orderings for tiebreakers
  • • Implement for any custom type

Monads

Encapsulate computations and chain operations while handling different concerns:

Maybe

Optional data with Just and Nothing

Either

Two possibilities with Left and Right

Effect

Deferred execution with error handling

Reader

Pass environment for dependency injection

Writer

Thread logs alongside results using monoids

Identity

Simple wrapper for organizing transformations

Monoids

Combine values with associative operations and identity elements:

Sum/Product: Number operations
Eq.All/Any: Equality logic
Predicate.All/Any: Boolean logic
Max/Min: Value selection
ListConcat: Combine lists
StringConcat: Combine strings
Ord: Compositional ordering