FunctionalXpp

Functional Programming Patterns in Modern C++ · 2016–2019

C++17 Template Metaprogramming Monads Parser Combinators Catch2

Why Functional C++?

C++ is not a functional language. But the patterns that make Haskell powerful — monadic composition, lazy evaluation, persistent data structures, parser combinators — are not language-specific ideas. They are design patterns that encode deep truths about how computation composes. FunctionalXpp asks: can these patterns be expressed in modern C++ without sacrificing type safety or performance?

This library was built during 2016–2019 as a deliberate study of functional programming through implementation. The discipline of translating Haskell abstractions into C++17 template metaprogramming forces a precise understanding of what each abstraction does versus what it merely looks like. You cannot implement a monad in C++ by accident.

Core Abstractions

Maybe Monad

A type-safe optional value that eliminates null pointer errors through the type system:

Maybe<int> result = Some(42);
Maybe<int> nothing = None<int>();

// Monadic chaining — computation short-circuits on None
auto doubled = result.map([](int x) { return x * 2; });
auto filtered = result.filter([](int x) { return x > 10; });

The key insight: Maybe<T> isn't just std::optional with a different name. It's a functor that supports map, a monad that supports bind (>>=), and these operations compose. Error propagation becomes implicit in the type structure rather than explicit in control flow.

Persistent Functional List

An immutable cons-cell linked list with structure sharing via smart pointers:

List<int> xs = make_list(1, 2, 3, 4, 5);
List<int> ys = cons(0, xs);  // ys shares xs's tail — O(1) prepend

int h = head(xs);       // 1
List<int> t = tail(xs); // [2, 3, 4, 5]

Persistent data structures are the backbone of functional programming. By making data immutable and sharing structure between versions, they eliminate a class of concurrency bugs while enabling efficient “copy-on-write” semantics through pointer sharing.

Parser Combinators

A combinator framework inspired by Graham Hutton's Programming in Haskell, where complex parsers are built from simple atomic parsers through composition:

// Atomic parsers
auto digit = satisfy(isdigit);
auto letter = satisfy(isalpha);

// Combinators: sequence (&), alternative (|), repetition
auto identifier = (letter & many(letter | digit));
auto number = many1(digit);

The parser type is itself monadic: Parser<T> is a function from input to ParsedResult<T>, and the bind operator (>>=) sequences parsers while threading state. This means arbitrary parsers compose without explicit state management — the monad handles it.

Lazy Views with CRTP

A chainable, lazy evaluation framework using the Curiously Recurring Template Pattern:

std::vector<int> nums{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

auto result = fxpp::view(nums)
    .filter([](int x) { return x % 2 == 0; })   // lazy
    .map([](int x) { return x * x; })             // lazy
    .collect();                                     // [4, 16, 36, 64, 100]

Operations chain lazily — no intermediate containers are allocated until collect() forces evaluation. The CRTP pattern allows each view layer (MapHeadedView, FilterHeadedView, FlatMapHeadedView) to inherit chainable methods without virtual dispatch overhead. This predates C++20 ranges by several years but explores the same design space.

Template Metaprogramming Techniques

The library exercises several advanced C++ techniques:

TechniqueWhere UsedPurpose
CRTPView systemStatic polymorphism for zero-cost method chaining
SFINAEContainer operationsConstrain template instantiation to valid types
Variadic templatesmake_list, PTreeType-safe variadic construction
Type traitsThroughoutCompile-time type inspection and transformation
Operator overloadingMonadic operators>>= for bind, & for tuple creation, | for alternatives
Smart pointersPersistent listStructure sharing with automatic memory management

Hierarchical Property Trees

A compile-time hierarchical data structure for type-safe nested configuration:

// Type-safe tree: keys and value types checked at compile time
using Config = PTree<
    PLeaf<int, "port">,
    PNode<"database",
        PLeaf<std::string, "host">,
        PLeaf<int, "connections">
    >
>;

Invalid key access becomes a compile error rather than a runtime crash. This pattern — encoding domain constraints in the type system — reappears throughout the later MayaPortal project where type signatures encode scientific propositions.

The Thread to MayaPortal

FunctionalXpp's abstractions reappear, matured, in MayaPortal's rendering engine:

FunctionalXpp (2016–2019)MayaPortal (2025–present)
Maybe<T> monadstd::expected<T, Error> with monadic and_then
Lazy views with CRTPPure-core / effectful-shell architecture
Parser combinators with bindRendering pipeline as typed compositions
Persistent data structuresImmutable GPU context (Reader pattern)
Operator overloading for DSLMonadic vocabulary: Reader, State, Expected, Writer

The progression is clear: FunctionalXpp explored whether functional patterns could work in C++. MayaPortal applies them to a real domain — GPU rendering — where composability and type safety directly improve the ability to reason about complex state transformations.

Technical Details

← Projects