Patty Pattern Matching for Nim

repository·master·Indexed 42 days ago

https://github.com/andreaferretti/patty

A pattern matching library for the Nim programming language that provides macros for constructing algebraic data types (variants) and performing expressive pattern matching. It supports named fields, positional matching, wildcards, and exhaustive checks. Includes the `variant` and `variantp` macros for creating private and public ADTs with automatic equality operators and constructor functions.

Tokens
1K
Snippets
5
Records
6
Agent score
5%

What's inside Patty

  1. Define a linked list using `variant`

    master

    The following example demonstrates how to use the variant macro to define a recursive data structure like a linked list and perform pattern matching on it.

    import patty
    
    proc `~`[A](a: A): ref A =
      new(result)
      result[] = a
    
    variant List[A]:
      Nil
      Cons(x: A, xs: ref List[A])
    
    proc listHelper[A](xs: seq[A]): List[A] =
      if xs.len == 0: Nil[A]()
      else: Cons(xs[0], ~listHelper(xs[1 .. xs.high]))
    
    proc list[A](xs: varargs[A]): List[A] = listHelper(@xs)
    
    proc sum(xs: List[int]): int = (block:
      match xs:
        Nil: 0
        Cons(y, ys): y + sum(ys[])
    )
    
    echo sum(list(1, 2, 3, 4, 5))
  2. Construct algebraic data types with `variant` and `variantp`

    master

    Patty provides macros to simplify the creation of algebraic data types (ADTs).

    variant macro

    Creates a private ADT within the current module. It automatically generates:

    • An enum for the variant kinds (marked {.pure.} to avoid name conflicts).
    • The object definition using a case statement.
    • An equality operator (==) that compares the actual contents of the variants.
    • Constructor functions for each variant (e.g., Circle(...)).

    variantp macro

    Creates a public ADT. It functions identically to variant but makes the types, fields, equality definition, and generated constructors public.

    Limitation: Field names must be unique across all branches of the variant (a limitation of Nim).

    variant Shape:
      Circle(r: float)
      Rectangle(w: float, h: float)
      UnitCircle
    
    # Usage:
    let c = Circle(5.0)
    let r = Rectangle(10.0, 20.0)
  3. Pattern match on variant objects using `match`

    master

    Patty allows you to perform pattern matching on Nim variant objects (algebraic data types). A variant object is typically an object with a case field (often named kind) that uses an enum to determine the object's layout.

    You can match using:

    • Named fields: Variant(field: variable_name)
    • Positional matching: Variant(variable_name, variable_name)
    • Wildcards (_): Use _ to skip binding a specific field, or use _ as a standalone pattern to act as a catch-all (translated to an else clause).

    Note: Checks are exhaustive; the Nim compiler will error if you miss a case.

    import patty
    
    # Assuming a variant object 'Shape' exists
    match myShape:
      Circle(r: radius):
        echo "radius is ", radius
      Rectangle(w: _, h: height):
        echo "height is ", height
      _:
        echo "something else"
  4. Pattern match on non-variant objects

    master

    You can use the match macro to deconstruct standard Nim objects by matching against their type and field values.

    type Person = object
      name: string
      age: int
    
    let p = Person(name: "John Doe", age: 37)
    
    match p:
      Person(name: n, age: a):
        echo n, "is ", a, " years old"