Skip to content

Patternia API Reference

Overview

Patternia exposes one public matching shape:

match(subject) | on(
  case_1,
  case_2,
  _ >> fallback
)

The pipeline is immediate. There is no deferred builder stage.


match(subject)

match(subject) creates the evaluation context for one subject value.

int x = 7;
auto r = match(x) | on(
  lit(7) >> 1,
  _ >> 0
);

Rules:

  • subject must be an lvalue.
  • Cases are evaluated in source order.
  • Matching uses first-match-wins semantics.

on(case1, case2, ...)

on(...) groups the case list consumed by match(subject).

match(x) | on(
  lit(1) >> "one",
  lit(2) >> "two",
  _ >> "other"
);

Rules:

  • The last case must be a wildcard fallback.
  • Each entry must be a pattern >> handler case expression.
  • Unreachable wildcard/alt ordering errors are diagnosed at compile time.

pattern >> handler

This is the core case-expression form.

lit(1) >> 42
$(is<int>) >> [](int v) { return v * 2; }
$(has<&Point::x, &Point::y>) >> [](int x, int y) { return x + y; }

Handler forms:

  • pattern >> value
  • pattern >> callable

Bindings are determined entirely by the pattern.


Wildcard _

_ is the public wildcard and fallback pattern.

match(x) | on(
  lit(1) >> "one",
  _ >> "other"
);

The wildcard does not bind values by itself.


Literal Patterns

lit(value)

Runtime literal match.

match(x) | on(
  lit(5) >> 42,
  _ >> -1
);

val<value>

Compile-time literal match. Useful when the literal is known at compile time and the lowering engine can consider static dispatch.

match(x) | on(
  val<1> >> 1,
  val<2> >> 2,
  _ >> 0
);

lit_ci(value)

Runtime ASCII case-insensitive string match.

match(s) | on(
  lit_ci("hello") >> 1,
  _ >> 0
);

Binding Patterns

$ and $(...)

Patternia keeps binding explicit.

$               // bind the whole subject
$(subpattern)   // bind under a subpattern

Examples:

match(x) | on(
  $ >> [](int v) { return v; },
  _ >> 0
);
match(v) | on(
  $(is<std::string>) >> [](const std::string &s) {
    return s.size();
  },
  _ >> 0
);

Binding rules:

  • No pattern binds implicitly.
  • Handler parameters follow binding order.
  • Patterns that do not bind produce zero-argument handlers.

Guard Attachment []

Attach a guard to a binding pattern with pattern[guard].

match(x) | on(
  $[PTN_LET(value, value > 0 && value < 10)] >> "small",
  _ >> "other"
);

Guard evaluation order:

  1. Match the pattern.
  2. Bind values.
  3. Evaluate the guard.
  4. Invoke the handler if the guard passes.

A guard failure only rejects the current case.


Guard Helpers

_0

Placeholder alias for a single bound value.

$[_0 > 5]

Use _0 when one binding is enough and the predicate reads clearly without an explicit name.

arg<N>

Indexed placeholder for general multi-binding guards.

$(has<&Point::x, &Point::y>)[arg<0> * arg<0> + arg<1> * arg<1> == 25]

rng(lo, hi, mode)

Range helper for single-bound-value guards.

$[rng(0, 10)]
$[rng(0, 10, pat::mod::open)]

Use callables for domain logic that does not read naturally as _0, arg<N>, or PTN_WHERE(...).

PTN_WHERE((names...), expr)

Use named guard parameters without writing the lambda yourself. The macro currently supports 1 to 5 names.

match(p) | on(
  $(has<&Point::x, &Point::y>)[PTN_WHERE((x, y), x == y)] >> "diagonal",
  _ >> "other"
);

PTN_WHERE(...) expands to a guard callable and composes with && / || like other guard predicates.

PTN_LET(name, expr)

Use the single-value form when a guard binds exactly one value and you want to name it explicitly.

match(x) | on(
  $[PTN_LET(value, value > 0 && value < 10)] >> "small",
  _ >> "other"
);

PTN_LET(name, expr) is equivalent to PTN_WHERE((name), expr).


Structural Matching has<&T::member...>

has<> describes structure. Wrap it with $(...) to extract values.

struct Point {
  int x;
  int y;
};

match(p) | on(
  $(has<&Point::x, &Point::y>) >> [](int x, int y) {
    return x + y;
  },
  _ >> 0
);

Properties:

  • Member order is explicit and stable.
  • Unlisted members are ignored.
  • Validation happens at compile time.

Variant Matching is<T> and alt<I>

is<T>

Type-based std::variant match.

match(v) | on(
  is<int> >> "int",
  $(is<std::string>) >> [](const std::string &s) {
    return "str:" + s;
  },
  _ >> [] { return std::string("other"); }
);

alt<I>

Index-based std::variant match.

match(v) | on(
  alt<0> >> "first",
  alt<1> >> "second",
  _ >> "other"
);

Rules:

  • is<T> requires T to appear exactly once.
  • alt<I> requires I to be in range.
  • Use $(...) when you want the alternative value bound into the handler.

Cached Case Packs

static_on(...)

Cache a stateless on(...) factory.

match(x) | static_on([] {
  return on(
    val<1> >> 1,
    val<2> >> 2,
    _ >> 0
  );
});

PTN_ON(...)

Convenience macro over static_on(...).

match(x) | PTN_ON(
  val<1> >> 1,
  val<2> >> 2,
  _ >> 0
);

The factory must be stateless.


Namespace Summary

The public surface is re-exported through namespace ptn:

  • match
  • on
  • lit, val, lit_ci
  • $
  • _
  • _0, arg, rng
  • has
  • is, alt

Minimal Example

#include <ptn/patternia.hpp>

int main() {
  using namespace ptn;

  int x = 2;
  int r = match(x) | on(
    lit(1) >> 10,
    lit(2) >> 20,
    _ >> 0
  );

  return r == 20 ? 0 : 1;
}