ArXiv: 1809.03252
🎯 Pitch
The Kleene star in pattern matching is stuck in flat lists, but this paper shows how to make it depend on the repeat count and traverse trees or graphs. The trick is treating the ellipsis as a first-class place in the pattern tree, allowing patterns like "the n-th inner list must have exactly n elements" or "find all ancestors" to be written declaratively without recursive helper functions.
1. Executive Summary
This paper introduces loop patterns, a new pattern-matching construct that extends the Kleene star operator (repeated patterns) to overcome two fundamental limitations: the inability to parameterize repeated sub-patterns by the current repeat count, and the restriction to list-like data structures where repetition appends to the tail. Loop patterns address these by (i) exposing an explicit index variable that can be referenced inside the repeated pattern and in subsequent patterns (e.g., matching the i-th list to contain i elements, or constraining successive elements to be consecutive integers via ,(+ 1 x_(- i 1))), and (ii) allowing the repeat pattern's expansion site (the ellipsis) to be placed anywhere in the pattern tree, enabling traversal of arbitrary user-defined data structures including trees and graphs. The paper demonstrates expressiveness through working examples in the Egison programming language—including a parameterized n-queens solver, ancestor enumeration in trees, and shortest-path search in graphs—establishing that loop patterns can represent patterns previously inexpressible with repeated patterns, though the formal semantics reveal additional complexity from the required end-number mechanism and multi-context expansion rules.
2. Context and Motivation
The Core Problem: Repeated Patterns Are Simultaneously Powerful and Crippled
Pattern matching is a fundamental programming language mechanism that allows programmers to concisely destructure and query data against structural templates. Among pattern-matching constructs, the Kleene star operator (also called the repeated pattern in languages like Mathematica and Racket) occupies a special role: it expresses repetition — a pattern that matches multiple consecutive elements of a data structure. The Kleene star originated in regular expressions [15] for matching repeated character sequences in strings, but its conceptual simplicity—"match this pattern zero or more times"—led to its adoption in general-purpose pattern-matching systems beyond string processing.
However, this adoption came with two severe restrictions that the paper identifies in Section 1. These restrictions are not accidental implementation details; they are baked into the fundamental semantic model of the repeated pattern as inherited from regular expressions.
Limitation 1: The pattern repeated cannot depend on the repeat count. In a classical repeated pattern, each repetition is structurally identical — the same sub-pattern is applied uniformly regardless of whether it's the first, fifth, or fiftieth repetition. This works well for regular expressions (a sequence of a characters is just a*) but breaks down for richer data patterns. Consider a list of lists where the n-th inner list must contain exactly n elements: [[a], [a,a], [a,a,a]]. A repeated pattern cannot express this because the length constraint on each inner list depends on its position index, and the repeat count is invisible to the pattern. Similarly, the pattern that matches lists of consecutive integers like [1,2,3,4] or [10,11,12] requires each element (except the first) to equal its predecessor plus one — a dependency across different repetitions of the pattern. Standard repeated patterns provide no mechanism for one repetition to access values bound in previous repetitions.
Limitation 2: The repeated pattern can only be applied to lists (and list-like structures). This restriction is subtler but equally fundamental. In a classical repeated pattern, the pattern repeated is always appended to the tail of the data structure — it consumes elements sequentially from left to right (or front to back). This works for lists, strings, multisets, and other flat sequential collections, but fails for hierarchical structures like trees and graphs. To traverse the ancestors of a tree node, you must move upward through the tree, not just rightward through a sequence. To find a path through a graph, you must follow edges in arbitrary directions. The tail-appending semantics of repeated patterns cannot express these traversal directions — as the paper states in Section 1, "the repeated patterns can be applied only to collection data such as lists and multisets."
Why These Limitations Matter: From Convenience to Expressiveness
These are not merely inconveniences. They represent expressiveness gaps — entire classes of patterns that programmers need to write but cannot, at least not without abandoning the pattern-matching paradigm and resorting to recursive functions with explicit conditionals.
The first limitation (no dependence on repeat count) affects any pattern where structure varies predictably with position. Beyond the examples above, this includes:
- Triangular matrices (the i-th row has i non-zero elements)
- Sequences with arithmetic or geometric progression constraints
- Patterns where the i-th element is constrained by a function of i
- Any pattern where the existence or structure of later elements depends on how many elements have been matched so far
The second limitation (lists only) affects pattern matching against the vast majority of non-trivial data structures used in modern programming. Trees (abstract syntax trees, XML/HTML documents, file systems, organizational hierarchies) and graphs (social networks, transportation networks, dependency graphs, knowledge bases) are ubiquitous. A pattern-matching system that cannot traverse these structures is limited to flat-data problems — a severe restriction for a general-purpose programming language.
The paper argues (implicitly through its examples in Section 5) that these limitations prevent pattern matching from being the primary control-flow mechanism for a wide range of algorithms that would otherwise benefit from its declarative, concise style. The n-queens solver (Section 5.1, Figures 2–3) illustrates this concretely: the four-queens version (Figure 2) can be written with hardcoded repeated patterns, but the general n-queens version (Figure 3) requires referential access to the current repeat count and to values bound in previous repetitions — it is inexpressible with classical repeated patterns.
Prior Approaches and Where They Fall Short
The paper situates its contribution within a landscape of prior work on extensible pattern matching, summarized in Section 2. The key distinction the paper draws is between work on user-customizable pattern matching (letting programmers define how patterns match against user-defined data types) and work on repeated patterns (the Kleene star family). These two lines of research have largely developed independently, and their intersection is where loop patterns live.
Customizable Pattern Matching Without Repeated Patterns
Several influential systems allow programmers to define pattern-matching behavior for user-defined data types through mechanisms like active patterns [12, 18], views [21], and first-class patterns [20]. These systems address a different limitation of traditional pattern matching — the inability to match against abstract data types or to decompose data in non-standard ways — but they do not address repetition. The paper specifically notes (Section 2):
"these proposals do not discuss on the repeated patterns. For example, active patterns [12, 18] applies its pattern-matching facility to graphs [13]. However, they use recursive functions for traversing graphs."
This is the critical observation: when existing customizable pattern-matching systems need to express repeated traversal (e.g., walking a graph), they fall back to recursive functions. The pattern-matching mechanism itself provides no abstraction for repetition; the programmer must manually write the recursion, manage the traversal state, and handle base cases. This defeats the purpose of using pattern matching for complex data structures — the pattern becomes just a local decomposition tool within a recursive function, rather than a declarative specification of the entire structure being queried.
The paper also notes (Section 2) that these customizable pattern-matching systems, with the exception of Egison [11], do not support non-linear pattern matching with multiple results. Non-linear patterns allow the same variable to appear multiple times in a pattern, constraining those positions to match equal values. Backtracking with multiple results means that when a pattern can match in multiple ways (e.g., a join pattern that splits a collection at different positions), the system explores all possibilities and collects the results. The paper argues that repeated patterns are "powerful especially when combined with non-linear pattern matching with backtracking" — a claim supported by examples like the n-queens solver (where the non-linear constraints on diagonals interact with the loop pattern's structural repetition) and the twin-primes finder in Section 3.
Regular-Tree Expressions: Repeated Patterns for Trees, but Without Count Access
The paper identifies regular-tree expressions (specifically the trx language [6]) as the closest prior work to addressing the second limitation (lists-only). Regular-tree expressions extend regular expressions to handle tree-structured data, introducing recursively defined patterns that can traverse tree edges in multiple directions. This overcomes the tail-appending restriction and allows repeated patterns to be applied to trees.
However, the paper identifies a crucial remaining gap (Section 2):
"However, they still suffer from the first limitation. The reason is because the recursively defined patterns do not provide a method for managing the repeat count."
In other words, trx solves the problem of where repetition can occur (arbitrary tree positions) but not the problem of how the repeated pattern varies with repetition count. The recursively defined patterns in trx are structurally identical at each recursive unfolding, just as classical repeated patterns are identical at each sequential repetition. There is no exposed index variable, no way to reference values from previous unfoldings, and no mechanism for the pattern to depend on how many times it has been recursively applied.
The paper thus positions loop patterns as solving both limitations simultaneously: the explicit index variable (and the ability to place the ellipsis anywhere) addresses both the count-dependence limitation and the structural limitation. The trx comparison is important because it shows that solving the structural problem alone (as trx did) leaves real expressiveness on the table — the n-queens solver, consecutive-sequence matching, and the traveling-salesman pattern (Figure 6) all require count dependence in addition to flexible placement.
Built-in Repeated Patterns in Mainstream Languages
Languages like Mathematica [4] and Racket [19] include repeated patterns (Mathematica calls them Repeated, Racket provides them through its extensible pattern matching). These systems handle repetition for lists but inherit both limitations described above. The paper does not dwell on these at length — the limitations are presented as fundamental properties of the repeated pattern construct, not as implementation bugs — but the contrast is implicit throughout. In Section 4.2, the paper specifically contrasts its hash-table-based storage of repeated bindings (indexed variables like $x_i) with Mathematica and Racket's collection-based storage, arguing that the hash-table approach makes it easier to reference values from arbitrary previous repetitions (e.g., x_(- i 1) in the consecutive-integer pattern).
Domain-Specific Query Languages
The paper mentions (Section 1) that domain-specific languages like Cypher [3] and Gremlin [17] (graph query languages) and parsing expression grammars [14] have "Kleene star like operators." These languages are highly specialized — Cypher and Gremlin are designed exclusively for graph traversal, not general-purpose pattern matching. The paper's goal is different: to provide a unified pattern-matching construct (loop patterns) that, when combined with a small set of primitive pattern constructors (like cons, join, nil, value patterns, and-patterns, not-patterns), can express the patterns that these domain-specific languages handle through extensive built-in functions. The paper makes this ambition explicit in Section 8:
"These query languages are focusing on handling only their target data structures and have many built-in functions to handle various patterns. On the other hand, our pattern-matching system allows users to describe various patterns for various data types in a unified way with a small number of pattern constructors and the loop patterns."
How This Paper Positions Itself
The paper positions loop patterns not as a replacement for the Kleene star, but as a generalization that subsumes its capabilities while extending them in two orthogonal dimensions. The extension is designed to be minimal — loop patterns add only a small number of new concepts (index variable, index range, end numbers, ellipsis pattern) to the existing language — but their interaction with Egison's existing features (non-linear patterns, backtracking, customizable matchers for arbitrary data types, multi-result match-all) creates a combinatorial expressiveness far beyond what the Kleene star alone provides.
The relationship to the Egison language [1, 11] is important context. Loop patterns are proposed as an extension to Egison, which already provides (from prior work):
- User-customizable pattern matching for arbitrary algebraic data types (via the
matcherexpression) - Non-linear patterns with backtracking (the ability to reference the same variable multiple times, with the system exploring all consistent bindings)
- Multiple results (the
match-allexpression returns a collection of all successful matches, not just the first) - Lazy evaluation (enabling pattern matching over infinite data structures)
The paper argues (implicitly through the examples in Sections 3–5) that loop patterns are "even more powerful when combined with" these features. The n-queens solver (Section 5.1) shows non-linear patterns (the diagonal constraints using !) interacting with loop patterns (the structural repetition of rows). The tree traversal (Section 5.2) shows customizable matchers (the algebraic-data-matcher for trees) interacting with loop patterns (the ancestor traversal). The graph example (Section 5.3) shows backtracking with multiple results (the match-all exploring all paths) interacting with loop patterns (the path-length parameterization).
The paper also acknowledges that loop patterns introduce semantic complexity. Section 6.2 discusses the "necessity of end numbers" — a design choice that adds complexity to the index range syntax but prevents runtime errors in cases where value patterns alone cannot delimit the end of iteration. Section 7 provides formal semantics (Figure 7) with four highlighted rules added to the base semantics from [11] for handling loop patterns and ellipsis expansion. The paper is candid that this complexity is a cost: Section 8 suggests that "research for finding simpler language constructs for constructing the loop patterns is also interesting because the semantics of the loop patterns presented in this paper is a bit complicated as a built-in language feature."
In summary, the paper positions loop patterns as a pragmatic generalization of the Kleene star that bridges the gap between flat-list regular-expression-style repetition and the structured-traversal needs of tree and graph pattern matching, while simultaneously introducing parameterization-by-repeat-count. The contributions are both conceptual (identifying and precisely characterizing the two limitations), design-oriented (the loop pattern construct itself, with its index range, end numbers, and ellipsis placement), and demonstrative (working examples showing patterns previously believed inexpressible).
3. Technical Approach
This is primarily a language design paper that proposes and formalizes a new pattern-matching construct (loop patterns) as an extension to the existing Egison pattern-matching system. The core idea is that by making the repeat count an explicit named variable accessible within the repeated pattern, and by allowing the programmer to control where pattern repetition expands (rather than always appending to the tail), a single construct can express patterns that previously required either hardcoded repetition, recursive functions external to the pattern-matching system, or were simply inexpressible.
3.1 Reader Orientation
The paper presents a pattern-matching construct called a loop pattern, which is a single syntactic form that generalizes the Kleene star operator along two independent axes: (1) it exposes the current repetition index as a named variable that can be referenced inside the repeated sub-pattern and in subsequent patterns, and (2) it decouples the site of pattern expansion from the tail position, allowing the repeated pattern to be placed anywhere in the pattern tree — inside tree nodes, at arbitrary graph edge positions, or nested within other loop patterns. The problem it solves is that classical repeated patterns are simultaneously essential (they express iteration concisely) and crippled (they cannot parameterize the repeated sub-pattern by count, and they only work for flat sequential data structures). The shape of the solution is to add a single new pattern form — (loop $i [start {ends} end-pat] repeat-pat end-pat) — with exactly one new expansion mechanism (the ellipsis ...) whose behavior is governed by a small, precisely specified set of rules.
3.2 Big-Picture Architecture
The loop pattern system extends Egison's existing pattern-matching engine with five interacting components:
-
Index variable (
$i): A user-named variable that the system initializes, increments, and makes accessible inside the repeat pattern and end pattern. This is the mechanism that overcomes Limitation 1 (no dependence on repeat count). -
Index range (
[start {end-values} end-pattern]): A specification of where the index variable starts, which values cause the loop to potentially terminate, and a pattern that must match the index when termination occurs. This includes the end numbers, a sorted list of integers that explicitly tells the system when to consider stopping — a design choice the paper defends in Section 6.1 as necessary to prevent infinite expansion. -
Repeat pattern (
repeat-pat): The sub-pattern that gets replicated for each iteration, with the index variable incremented on each expansion. This pattern can reference the index variable and any values bound in previous iterations. -
End pattern (
end-pat): The sub-pattern that replaces the expansion site when the index variable reaches an end number, complementing or replacing the repeat pattern. -
Ellipsis pattern (
...): A placeholder in the pattern tree that marks where expansion occurs. Crucially, the ellipsis can be placed anywhere in a pattern — inside constructors, nested within other patterns, at any depth. When the pattern matcher encounters an ellipsis, it consults the top of the loop context stack to decide whether to replace it with the repeat pattern, the end pattern, or both.
These components interact through a loop context stack maintained by the pattern-matching engine. When a loop pattern is encountered during matching, a new loop context is pushed containing the index variable binding, the list of end numbers, and the repeat/end patterns. When an ellipsis is encountered, the engine pops and examines the top loop context, checks the current index value against the end numbers, and performs the appropriate expansion. This stack-based design (detailed in the formal semantics in Figure 7) allows loop patterns to nest arbitrarily.
3.3 Roadmap for the Deep Dive
- First, the syntactic structure of loop patterns and their component parts (index variable, index range, repeat pattern, end pattern, ellipsis), since everything else builds on understanding what a loop pattern looks like and what each part means.
- Second, the ellipsis expansion mechanism — the runtime behavior that determines, at each step, whether the ellipsis becomes a repeat pattern, an end pattern, or both — since this is the core operational semantics that distinguishes loop patterns from classical repeated patterns.
- Third, the index range semantics and the necessity of explicit end numbers, since this is the most subtle design choice and is defended in Section 6.1 against a seemingly simpler alternative.
- Fourth, the interaction with indexed pattern variables (the hash-table-based binding mechanism), since this is how programmers access values bound in previous iterations and is what enables patterns like consecutive-sequence matching.
- Fifth, how loop patterns compose with Egison's existing features (customizable matchers, non-linear patterns, backtracking,
match-allmulti-result semantics, let-patterns), since the paper's expressiveness claims depend on this composition, not on loop patterns in isolation. - Sixth, the formal semantics (Figure 7), which specifies the operational behavior precisely using a matching-state machine with a loop context stack, providing the definitive reference for implementers.
3.4 Detailed, Sentence-Based Technical Breakdown
Syntactic Structure of Loop Patterns
A loop pattern is a single syntactic form defined in Figure 1's grammar:
(loop $ident [expr expr pattern] pattern pattern)
Concretely, a loop pattern has four sub-components:
1. Index variable. This is written as $ident (e.g., $i, $j) and behaves like an ordinary pattern variable with one crucial difference: the system automatically manages its binding — initializing it to the start number, incrementing it on each repeat expansion, and terminating the loop when it reaches the end numbers. The index variable is in scope within both the repeat pattern and the end pattern, meaning the programmer can write expressions like $x_i (an indexed pattern variable keyed by the current index) or , (+ 1 x_(- i 1)) (a value pattern that references the previous iteration's binding).
2. Index range. Written as [start-num end-numbers end-pattern], where:
-
start-numis an expression evaluating to an integer. This is the initial value assigned to the index variable before any expansion occurs. It cannot be omitted — the paper provides syntax sugar for omitting end numbers and the end pattern, but never the start number. -
end-numbersis an expression evaluating to a sorted list of integers (e.g.,{2 3},{n}, or the infinite sequence(from 1)). These are the values at which the loop might terminate. Critically, the system uses this explicit list — not pattern matching — to know when to stop. The paper explains in Section 6.1 that this is necessary because value patterns alone cannot reliably delimit iteration (a value pattern like,2would match 2, but would also match 3, 4, ... — the system has no way to know that 3 should not be attempted next). -
end-patternis a pattern that is matched against the index variable's value when the index reaches one of the end numbers. This allows the programmer to capture which end number was reached: for example,$nas the end pattern bindsnto 2 or 3 when the end numbers are{2 3}, enabling the pattern to know how many iterations actually occurred.
Syntax sugar for the index range (described in Section 4.1). Since the full three-element form is verbose, the paper defines several shorthands:
| Written form | Expands to | Meaning |
|---|---|---|
[start] | [start (from start) _] | Loop forever (infinite end numbers from the start onward, wildcard end pattern) |
[start ends] | [start ends _] | Loop with specified end numbers, wildcard end pattern |
[start end-val] | [start {end-val} _] | Loop with a single end value (converted to a one-element collection) |
[start end-pat] | [start (from start) end-pat] | Loop forever, but capture the termination index via the end pattern |
3. Repeat pattern. This is an ordinary pattern (any valid Egison pattern) that gets replicated for each iteration where the index variable has not yet reached an end number. The repeat pattern typically contains an ellipsis (...) somewhere inside it — this is where the next expansion will occur. In the simplest usage, the repeat pattern is something like <cons $x_i ...> (consume one element, bind it to x_i, then continue expanding at the ellipsis position).
4. End pattern. This is an ordinary pattern that replaces the ellipsis when the index variable reaches an end number. For the final end number, only the end pattern is placed at the ellipsis site (no further repeat pattern). For intermediate end numbers, both the end pattern and the repeat pattern are placed, representing one possible termination point and one continuation point — this is how [1 {2 3} $n] produces results for both 2 iterations and 3 iterations.
The ellipsis pattern. The ellipsis pattern ... is a special atomic pattern (Figure 1 grammar) that acts as a placeholder. It is not matched against the target data directly; instead, when the pattern-matching engine encounters it, it replaces the ellipsis with other patterns based on the current loop context. The ellipsis is syntactically part of the repeat pattern and/or end pattern — typically placed at the position where the pattern should continue growing.
Example decomposition. Consider the comb2 pattern from Section 4.1:
(loop $i [1 2]
<join _ <cons $x_i ...>>
_)
- Index variable:
$i - Index range:
[1 2]→ expands to[1 {2} _](start at 1, single end number 2, wildcard end pattern) - Repeat pattern:
<join _ <cons $x_i ...>>(split the collection, consume one element and bind it tox_i, with the ellipsis where further expansion happens) - End pattern:
_(the wildcard — when the loop terminates, match nothing)
This describes the expansion: at i=1, expand to <join _ <cons $x_1 ...>>; at i=2, expand to <join _ <cons $x_2 _>> (end pattern replaces the ellipsis). The full expanded pattern becomes:
<join _ <cons $x_1 <join _ <cons $x_2 _>>>>
which matches two elements from a list and binds them to x_1 and x_2.
The Ellipsis Expansion Mechanism
The ellipsis expansion mechanism is the core operational semantics of loop patterns. It is specified formally in Figure 7 (the four highlighted matching-state rules) and described procedurally in Section 4.1. The mechanism answers a single question: when the pattern matcher encounters an ellipsis ..., what pattern(s) should replace it?
The answer depends on three pieces of information stored in the current loop context (the top of the loop context stack): the current value of the index variable (let us call it i), the list of end numbers (let us call it [e1, e2, ..., ek] in sorted order), and the triple of patterns (end-num-pat, repeat-pat, end-pat). The behavior follows three cases:
Case 1: i is not equal to any end number. This means the loop is in a "definitely continuing" state — the index has not yet reached a point where termination is possible. In this case, the ellipsis is replaced only with the repeat pattern, and the index variable is incremented (i.e., the loop context is updated with i+1). The target data remains the same — the repeat pattern will be matched against whatever part of the target data is currently being processed.
Case 2: i equals an end number that is not the last end number. This means the loop has reached a "branching" point — the pattern matching could either terminate here (producing one result) or continue (producing another result). In this case, the ellipsis is replaced with two alternatives:
- Alternative A: the end pattern followed by the end-num-pattern matched against the index value. This represents terminating the loop at this point. No further loop context is pushed — the loop is done.
- Alternative B: the repeat pattern, with the index variable incremented. This represents continuing past this end number to the next iteration.
Both alternatives are explored (this is where backtracking with multiple results comes in). The pattern-matching engine tries both paths and collects all successful matches.
Case 3: i equals the last end number. This means the loop has reached its final possible termination point. In this case, the ellipsis is replaced only with the end pattern followed by the end-num-pattern matched against the index value. There is no continuation alternative — the loop must terminate here.
Why end numbers are ordered and explicit. Cases 2 and 3 rely on the system knowing (a) whether the current index is an end number, and (b) whether it is the last end number. The end numbers list provides this information explicitly. Without an explicit list, the system would need to infer termination points from the end pattern alone — but as Section 6.1 explains, a value pattern like ,2 succeeds for 2 and fails for 3, but the failure merely causes backtracking, not termination: the system would try 3, find it fails, then try 4, find it fails, and so on indefinitely (or until a resource limit). The end numbers list gives the system a finite, known-in-advance set of stopping points, which is essential for termination guarantees.
Example walkthrough: comb2or3. Consider the pattern from Section 4.1:
(loop $i [1 {2 3} $n]
<join _ <cons $x_i ...>>
_)
- Start:
i = 1, end numbers ={2, 3},iis not in end numbers → Case 1. Expand to<join _ <cons $x_1 ...>>withiincremented to 2. - Now
i = 2, which equals the first end number (not the last since 3 follows) → Case 2. Two alternatives:- Alternative A (terminate at 2): Replace
...with_(end pattern) and match$nagainsti=2. Expansion:<join _ <cons $x_1 <join _ <cons $x_2 _>>>>withnbound to 2 — this matches two-element combinations. - Alternative B (continue past 2): Replace
...with<join _ <cons $x_2 ...>>(repeat pattern) withiincremented to 3.
- Alternative A (terminate at 2): Replace
- For Alternative B, now
i = 3, which equals the last end number → Case 3. Replace...with_(end pattern) and match$nagainsti=3. Expansion:<join _ <cons $x_1 <join _ <cons $x_2 <join _ <cons $x_3 _>>>>>withnbound to 3 — this matches three-element combinations.
The result: the single comb2or3 pattern produces matches for both two-element and three-element combinations, with $n telling the body expression how many elements were actually extracted.
The stack-based design for nesting. Loop contexts form a stack (denoted Λ in Figure 7). When a (loop ...) pattern is encountered, a new context is pushed. When an ellipsis is encountered during matching, the top context is used for the expansion decision. This means that nested loop patterns — like the double loop in the n-queens solver (Figure 3) — work correctly: the inner loop's ellipsis consults the inner loop context, while the outer loop's ellipsis (after the inner loop finishes) consults the outer loop context. The stack discipline ensures that the correct loop context is always accessible at the correct nesting level.
The Necessity of End Numbers: Why Value Patterns Alone Are Not Enough
Section 6.1 is a crucial piece of the technical argument because it defends what might otherwise seem like an unnecessarily complicated design. The question is: since the index range already contains an end-pattern, why do we also need an explicit list of end-numbers? Couldn't the system simply iterate the index variable (1, 2, 3, ...) at each step, try matching the current index against the end pattern, and stop when the match succeeds?
The paper's answer is no, and the justification is grounded in the operational semantics of backtracking pattern matching:
The problem with implicit termination. If the index range were [1 ,2] (start at 1, end pattern is the value pattern ,2), the system would proceed as follows:
i = 1: try matching 1 against,2. This fails (1 ≠ 2), so the repeat pattern is expanded withi = 2.i = 2: try matching 2 against,2. This succeeds, so the end pattern is placed and the loop can terminate here. But the pattern-matching system, which explores all possibilities via backtracking, would also continue: what abouti = 3?i = 3: try matching 3 against,2. This fails, so the system backtracks — but it has already produced the result ati = 2. The failure ati = 3does not erase the successful result ati = 2.
This seems fine for simple cases, but the paper identifies a fatal problem with the n-queens solver (Section 6.1). Consider the inner loop:
(loop $j [1 (- i 1)] ...)
With the explicit-end-numbers design, j iterates from 1 to i-1, exactly as intended — checking diagonal constraints against all previously placed queens. With a value-pattern-only design [1 ,(- i 1)], the system would also try j = i (since the value pattern ,(- i 1) would succeed at j = i-1, but backtracking would continue exploring). When j = i, the pattern references a_j inside a value pattern — but a_i has not been bound yet (it is the pattern variable currently being matched in the outer loop). This causes an unbound variable error.
Why explicit end numbers prevent this. With end numbers [1 {(- i 1)} _], the system knows that i-1 is the last end number. When j reaches i-1, Case 3 applies: only the end pattern is placed, and the loop terminates. There is no attempt to explore j = i — the explicit end number list tells the system definitively "stop here, do not continue." The explicit list acts as a declarative bound on iteration that is checked before any pattern matching occurs, preventing runaway exploration.
The complexity tradeoff. The paper acknowledges that the end number mechanism adds complexity: "the semantics of the loop patterns presented in this paper is a bit complicated as a built-in language feature" (Section 8). The alternative — using value patterns alone — would be syntactically simpler but semantically unsound for patterns that reference future bindings. The paper's position is that correctness and termination guarantees justify the additional mechanism.
Indexed Pattern Variables and the Hash-Table Binding Mechanism
A loop pattern's index variable is useful on its own (e.g., $i in the pattern [1 (- i 1)] as the end number of an inner loop), but its power is magnified by indexed pattern variables — pattern variables with integer indices, written as $x_1, $x_i, $x_(- i 1), etc. These are the mechanism by which different iterations of a loop can bind values to distinct names, and by which later iterations can reference values bound in earlier iterations.
Syntax and semantics of indexed variables (Section 4.1). An indexed variable has the form $ident_expr ... — a dollar sign, an identifier, an underscore, and an expression (which may be followed by additional underscore-expression pairs for multi-dimensional indexing). The expression after the underscore is evaluated to an integer at pattern-matching time. For example:
$x_1— bind the matched value to key1in the hash for variablex$x_i— bind the matched value to the key equal to the current value ofi(the loop index)$x_(- i 1)— bind to keyi-1$a_(- i j)— bind to keyi - j(two indices)
The underlying hash-table model. The paper contrasts its approach with Mathematica and Racket explicitly (Section 4.2):
"In Mathematica [4] and Racket [19], the values bound to a repeated pattern are stored as elements of a collection. However, they are stored in a hash table in our language."
When a value is bound to an indexed pattern variable $x_k, the system checks whether x is already bound:
- If
xis not bound, a new hash table is created, the value is stored at keyk, andxis bound to this hash. - If
xis already bound to a hash, the value is added at keyk(or updated if keykalready exists).
This hash-table model has two crucial advantages for loop patterns:
-
Random access by index. The programmer can reference
x_iorx_(- i 1)at any point in the pattern, regardless of when that value was bound. In a collection-based model, accessing the "previous" binding requires knowing the current length of the collection and indexing into it — possible but less direct. -
Sparse and non-sequential keys. The indices do not need to be consecutive integers starting from 1. In the n-queens solver (Figure 3), the outer loop uses
$a_iwithiranging from 1 ton, while the inner loop referencesa_jwithjranging from 1 toi-1. The hash table maps queen positions by row index, and the inner loop can check any queen's position by its row number without considering order.
Expressions in indices. The index is not restricted to literal integers — it can be any expression that evaluates to an integer. This is what enables patterns like ,(+ 1 x_(- i 1)) in the consecutive-integer example (Section 4.2): the expression (- i 1) computes the previous iteration's index, and x_(- i 1) retrieves the value bound in that iteration. The ability to compute indices dynamically is what makes the "refer to values bound in previous repetitions" capability work.
Relationship to loop pattern expansion. When a loop pattern's repeat pattern contains $x_i, each expansion of the repeat pattern increments i, so each iteration binds to a fresh key. The body expression can then retrieve all bound values using (map (lambda [$i] x_i) (between 1 n)) — construct a list of keys from 1 to n (where n was bound by the end pattern) and retrieve the value at each key. This is the standard idiom for collecting all values bound across loop iterations.
Interaction with Egison's Existing Features
Loop patterns do not exist in isolation. The paper's expressiveness claims depend critically on how loop patterns compose with Egison's pre-existing pattern-matching features. This subsection explains each interaction.
Customizable matchers for arbitrary data types. Egison allows users to define how patterns match against user-defined algebraic data types using the matcher expression [11]. For trees (Section 5.2), the paper defines:
(define $tree (algebraic-data-matcher
{<leaf string>
<node string (multiset tree)>}))
This tells the pattern-matching engine that leaf takes one argument (matched as a string) and node takes two arguments (a string and a multiset of trees). The loop pattern can then traverse this tree structure because the ellipsis can be placed inside a node pattern:
(loop $i [1 $n]
<node $c_i <cons ... _>>
<leaf ,"Egison">)
Here the repeat pattern places the ellipsis inside a cons inside a node — meaning each repetition moves one level up the tree (from a leaf to its parent node). This is impossible with classical repeated patterns because they always append to the tail, never "wrap around" a pattern constructor.
Non-linear patterns with backtracking. Non-linear patterns allow the same variable to appear multiple times, constraining all appearances to match equal values. In the four-queens solver (Figure 2), the constraints ! ,(- a_1 1) and ! ,(+ a_1 1) appear multiple times with different indices. In the general n-queens solver (Figure 3), the inner loop pattern:
(loop $j [1 (- i 1)]
(& !,(- a_j (- i j)) !,(+ a_j (- i j)) ...)
$a_i)
contains non-linear references to a_j (previously bound queen positions) and uses an and-pattern (&) as an as-pattern (matching $a_i while simultaneously checking constraints). The loop pattern provides the structural repetition; the non-linear patterns provide the equality and inequality constraints. Together they express the full n-queens constraint: for each new queen a_i, check against all previous queens a_j that they do not share a diagonal (a_j ± (i - j) ≠ a_i).
Multiple results via match-all. The match-all expression (Section 3) evaluates its body for every successful pattern match and collects all results into a collection. This is essential for the graph examples in Section 5.3, where there may be multiple paths through a graph. The pattern:
(match-all graph-data graph
[(loop $i [2 $n]
<cons <edge ,x_(- i 1) $x_i> ...>
<cons <edge ,x_(- n 1) (& ,e $x_n)> _>)
(map (lambda [$i] x_i) (between 1 n))])
explores all paths from the start node to the end node, with the loop pattern parameterizing the path length. For each successful match, the body constructs the list of nodes [x_1, x_2, ..., x_n] visited along that path. The shortest path is found by taking the car (first element) of the result collection — since shorter paths correspond to smaller n, and the loop tries all possible lengths, the first successful match in the lazy evaluation order is the shortest path.
Lazy evaluation. Egison uses lazy evaluation, which means match-all can return results incrementally and pattern matching over infinite data structures is possible. This is mentioned in Section 3 as enabling "pattern matching that may yield infinitely many results." In the context of loop patterns, lazy evaluation means that the system does not need to expand all possible iterations eagerly — it expands on demand, which is essential when the end numbers are (from 1) (an infinite sequence) and the programmer only consumes a finite prefix of results.
Let-patterns inside patterns. Section 5.3 introduces the let-pattern:
(let {[$x_1 s]} ...)
This binds a pattern variable inside the pattern before the main pattern-matching proceeds. In the graph example, it binds the start node s to $x_1, avoiding the need for special-case handling of the first edge in the path. The let-pattern interacts naturally with loop patterns because it establishes the initial binding that the loop's first iteration references (x_(- i 1) when i=2 refers to x_1, which is bound by the let).
Pattern constructors: join, cons, nil. These are pattern constructors (not data constructors) defined by the matcher for lists. join is particularly important — it splits a collection into two parts at some position, with all possible split points explored via backtracking. The repeated use of join inside a loop pattern is what enables the comb function: each iteration of the loop applies join again, splitting off one more element. The ellipsis placement inside join's second argument (the remainder) is what makes this work — each repetition processes the "rest" of the collection.
Value patterns. A value pattern ,expr matches when the target data is equal to the value of expr. This is used extensively in loop pattern examples: ,(+ 1 x_(- i 1)) matches the integer that is one more than the previous matched integer; ,(- a_j (- i j)) matches a specific integer (the diagonal-attack position). Value patterns are the mechanism by which constraints computed from loop index variables and previously bound values are checked against the target data.
And-patterns as as-patterns. The and-pattern (& pat1 pat2 ...) succeeds when all sub-patterns match the same target. In the n-queens solver, it is used as (& !,(- a_j (- i j)) !,(+ a_j (- i j)) $a_i) — match the target against $a_i (binding it to the new queen's row) while simultaneously checking that the target is not equal to the diagonal-attack positions. This is a standard as-pattern idiom, but it interacts with loop patterns by allowing the repeated constraints (the inner loop checking against each previous queen) to be conjoined with the variable binding.
Formal Semantics: The Loop-Pattern-Specific Rules
Figure 7 presents the formal semantics of Egison pattern matching with loop patterns. The paper highlights four rules (highlighted in the figure, though the highlighting is not visible in text) that are specific to loop patterns, building on the base semantics from [11]. This subsection explains these rules in operational terms.
The matching-state structure. A matching state in Egison's semantics consists of (Figure 7 notation):
- A stack of matching atoms (denoted
®a): each atom is a pair(p ∼m v)representing a patternpto be matched against a valuevunder matcherm. The...pattern is a matching atom whose pattern is the ellipsis. - An environment
Γ: bindings from pattern variables to values. - An intermediate result
∆: accumulated bindings from sub-matching (used for constructing the final result). - A stack of loop contexts
Λ: each loop context is a quadruple({i 7→ n}, {e1, e2, ...}, (p1, p2, p3))where{i 7→ n}is the current binding of the index variableito an integern,{e1, e2, ...}is the sorted list of end numbers, and(p1, p2, p3)are the end-number pattern, repeat pattern, and end pattern respectively. The stack is initially empty (denotedϵ).
The matching engine proceeds by repeatedly applying transition rules to the current matching state until it reaches a state where all matching atoms have been processed (the stack is empty) or no rule applies (failure).
Rule 1: Creating a loop context. When the top matching atom has a loop pattern (loop $i [M N p1] p2 p3) to be matched against a value v:
The rule evaluates M (obtaining an integer n) and N (obtaining a list of end numbers {ei}). It then creates a new loop context ({i ↦ n-1}, {ei}, (p1, p2, p3)) and pushes it onto the loop context stack. The matching atom for the loop pattern is removed from the stack. Note that the index is initialized to n-1 — this is one less than the start number because the first ellipsis expansion will increment it to n (the start value).
This rule is the entry point for loop pattern semantics. After it fires, the loop pattern itself is no longer on the matching stack — the loop has been "unfolded" into a context that will govern subsequent ellipsis expansions.
Rule 2: Ellipsis expansion when the index is not at an end number. When the top matching atom is an ellipsis ... to be matched against a value v, and the top loop context has index i and end numbers {e1, e2, ...} where i is not equal to e1 (the first/smallest end number):
This rule replaces the ellipsis matching atom with the repeat pattern p2 matched against the same value v, and increments the index variable in the loop context to i+1. The rest of the matching stack (®a) is preserved. This is the continue case — no branching occurs because termination is not yet possible.
Rule 3: Ellipsis expansion at an end number (not the last). When the top matching atom is an ellipsis, the top loop context has index i equal to the first end number e1, but there are more end numbers remaining ({e_i}_i' is non-empty):
This is the branching case. The ellipsis is replaced with two alternative matching-state continuations:
- Termination branch (top row): The end-pattern
p3is placed as the next matching atom (matched against the same valuev), followed by the end-number patternp1matched against the index valuei(under thesomethingmatcher sinceiis a raw integer). The loop context is removed from the stack (popped back toΛ). This branch represents the loop stopping at this iteration. - Continuation branch (bottom row): The repeat pattern
p2is placed as the next matching atom (matched againstv), the index is incremented toi+1, and the end number list is trimmed to excludee1(the just-processed end number). The loop context remains on the stack. This branch represents the loop continuing past this end number.
Both branches are explored via backtracking, and results from both are collected (for match-all).
Rule 4: Ellipsis expansion at the last end number. When the top matching atom is an ellipsis, the top loop context has index i equal to the only remaining end number e1:
This is the forced termination case. The ellipsis is replaced only with the termination branch: end pattern p3 matched against v, followed by end-number pattern p1 matched against i. The loop context is popped. No continuation branch is generated — the loop must terminate here.
Why the rules use something for matching the index variable. In all rules where the end-number pattern p1 is matched against the index value i, the matcher is something (Egison's built-in matcher that handles only wildcards and pattern variables). This is because the index variable i is a raw integer, not an algebraic data type — there is no structural decomposition to do, only binding.
The relationship to the base semantics. The four highlighted rules are the only additions to the base pattern-matching semantics from [11]. All other rules (for matching inductive patterns, value patterns, and-patterns, or-patterns, not-patterns, pattern variables, etc.) are unchanged. This means loop patterns are a conservative extension — any pattern that does not use (loop ...) or ... behaves identically to the base semantics.
Computational complexity. The paper states in Section 6.2:
"A loop pattern is expanded only when it is necessary. Therefore, the time complexity of pattern matching using loop patterns is completely same with pattern matching written not using them."
This is essentially claiming zero overhead: loop patterns are a syntactic abstraction that expands at pattern-matching time to the same matching atoms that would be present in a hand-expanded pattern. The branching introduced by Rules 3–4 is the same branching that would occur if the programmer wrote out the alternatives explicitly. The computational cost is determined by the number of matching possibilities explored (which depends on backtracking), not by the loop pattern mechanism itself.
Summary of Design Choices and Their Justifications
-
Explicit index variable over implicit count: The paper names the index variable (e.g.,
$i) rather than providing a built-in function likerepeat-count. This allows the index to be referenced in expressions ((- i 1),(- i j)), bound by the end pattern ($ncaptures the final count), and used as a key in indexed pattern variables ($x_i). An implicit count would be less flexible — the programmer couldn't compute with it or nest loops with distinguishable indices. -
Explicit end numbers over value-pattern-only termination: Defended in Section 6.1. Value patterns alone do not provide a termination guarantee because the system cannot distinguish "this pattern failed, so backtrack" from "this pattern will never succeed for any larger index, so stop iterating." The explicit sorted list of end numbers provides a computable, finite specification of all possible termination points, enabling the system to generate the correct branching structure without infinite search.
-
Hash-table storage over collection storage for repeated bindings: Defended implicitly in Section 4.2. A hash table allows random access by arbitrary integer keys, which supports patterns that reference arbitrary previous iterations (e.g.,
x_(- i 1),a_jwherejis not necessarilyi-1). A sequential collection would require knowing the current position in the sequence and computing offsets, which is more error-prone and less general. -
Ellipsis as an explicit placeholder over implicit tail-appending: The paper places the ellipsis explicitly in the pattern tree, allowing the programmer to control where the repeated pattern expands. This is what enables tree traversal (the ellipsis inside a
nodeconstructor), graph traversal (the ellipsis inside anedgeconstructor in acons), and nested loops (inner loop's ellipsis inside the outer loop's repeat pattern). Implicit tail-appending (as in classical repeated patterns) would restrict all repetition to sequential consumption, which is exactly the Limitation 2 the paper aims to overcome. -
Loop context stack over single global context: The stack design (Λ in Figure 7) enables arbitrary nesting of loop patterns. Each nested loop pushes its own context, and ellipses always consult the top context. This ensures that an inner loop's ellipsis does not interfere with an outer loop's expansion, and vice versa. A single global context would break under nesting (the inner loop's termination would incorrectly affect the outer loop).
-
Index initialized to
n-1with pre-increment semantics overnwith post-increment: The formal semantics initializes the index ton-1and increments it before the first expansion (Rule 2 increments fromitoi+1when expanding the repeat pattern). This means the repeat pattern sees the index starting at the start numbern, notn-1. The post-increment-after-expansion alternative would require the start number to ben+1or would cause the first iteration to see the wrong index. The pre-increment design is the natural choice given that the increment happens as part of ellipsis expansion. -
somethingmatcher for end-pattern matching over the target's matcher: In the formal semantics, the end-number pattern is matched against the index value using thesomethingmatcher, not the matcher of the target data. This is because the index is an integer produced by the loop mechanism, not part of the target data structure. Using the target's matcher would be a type error (e.g., trying to match an integer against a tree pattern) and would require the matcher to handle values outside its domain.
4. Key Insights and Innovations
Innovation 1: Framing the Two Limitations as a Unified Expressiveness Problem, Not Separate Feature Requests
The paper's most fundamental conceptual contribution is not the loop pattern construct itself, but the diagnosis that the Kleene star's limitations — no dependence on repeat count, and restriction to list-like structures — share a common root cause and therefore admit a common solution. Prior to this work, these two limitations appeared unrelated. The first (can't parameterize by count) seemed like a missing feature in the binding model — you'd fix it by adding a counter variable. The second (lists only) seemed like a structural restriction in the traversal model — you'd fix it by extending the pattern language to trees, as trx [6] did with recursively defined patterns. These were treated as separate problems by separate communities: the repeated-pattern community (Mathematica, Racket) cared about count access but not trees; the tree-expression community (trx) cared about hierarchical traversal but not count parameterization.
The paper's diagnostic move is to identify that both limitations are consequences of the same underlying design: the implicit, position-dependent expansion of the repeated pattern. In classical repeated patterns, the expansion site is implicitly the tail of the data structure, and the repeat count is an invisible, inaccessible counter managed entirely by the system. Because the expansion site is implicit, it can only be at the tail (causing the lists-only restriction). Because the count is invisible, no sub-pattern can depend on it (causing the parameterization restriction). The paper reframes these not as two missing features but as two symptoms of a single design flaw: the repeated pattern conflates what repeats with where repetition happens and how many times.
This reframing is significant because it implies that a single structural change — decoupling the expansion site from the tail position and exposing the count as a named variable — can address both limitations simultaneously. The loop pattern's design (explicit ellipsis placement + named index variable) is the direct consequence of this diagnosis. The paper does not present loop patterns as "repeated patterns plus a counter" or "repeated patterns plus tree support"; it presents them as a unified generalization that subsumes both extensions because they are different facets of the same underlying abstraction.
Evidence for this unified-framing claim is structural rather than quantitative: the paper's examples in Section 4.2 demonstrate both capabilities in the same construct. The consecutive-integer pattern ,(+ 1 x_(- i 1)) uses the index variable for parameterization; the tree traversal pattern <node $c_i <cons ... _>> uses explicit ellipsis placement for hierarchical traversal. They are not separate features — they are different uses of the same (loop ...) form with the same semantics.
Innovation 2: The "End Numbers" Mechanism as a Solution to a Genuine Semantic Difficulty in Pattern-Delimited Iteration
Section 6.1 presents what might initially appear to be a minor design detail — why the index range needs an explicit sorted list of end numbers in addition to an end-number pattern — but this discussion reveals a nontrivial semantic insight about pattern-delimited iteration that, to the paper's credit, it does not trivialize. The insight is: in a backtracking pattern-matching system with non-linear patterns, value-pattern-based termination is not a reliable substitute for declarative bounds on iteration.
This is not a performance optimization or a syntactic convenience; it is a correctness requirement. The paper demonstrates this through a concrete counterexample (the n-queens inner loop) where a seemingly natural alternative — let the system iterate the index variable and check it against the end pattern at each step — causes an unbound-variable error at runtime. The error arises because backtracking explores iterations beyond the intended bound, and those iterations reference pattern variables not yet bound.
The conceptual contribution here is the identification of a class of patterns where iteration bounds must be known before pattern matching begins, not discovered during it. This is a distinction that does not arise in simpler pattern-matching systems (regular expressions, first-order functional patterns) because they lack the combination of non-linear patterns, backtracking, and value-pattern constraints on future bindings. The paper is implicitly arguing that adding repetition to a backtracking pattern matcher with non-linear constraints creates a phase-ordering problem: you cannot use pattern matching to discover the iteration bound if the pattern being matched depends on variables that are only bound after the bound is known.
The explicit end-numbers list solves this by making the iteration bound a static declarative specification evaluated from expressions available in the current environment (e.g., {n}, {(- i 1)}, (from 1)) rather than a pattern-matching discovery. This is a genuine design insight rather than an implementation convenience, and it connects to broader issues in declarative programming about the interaction between binding time and control flow.
The paper's frankness about the resulting complexity — "the semantics of the loop patterns presented in this paper is a bit complicated as a built-in language feature" (Section 8) — strengthens this contribution. It acknowledges that the complexity is a cost, not a feature, and positions it as an open problem ("research for finding simpler language constructs... is also interesting"). This is the kind of negative-result-adjacent insight that pushes language design forward: identifying where a seemingly simpler design fails, and why.
Innovation 3: The Hash-Table Binding Model for Repeated Variables as an Enabler of Arbitrary Cross-Iteration References
The paper makes a design choice that is easy to overlook: values bound in different iterations of a loop pattern are stored in a hash table keyed by integer indices, rather than in a sequential collection as in Mathematica [4] and Racket [19]. The paper mentions this in Section 4.2 almost in passing, but it is a genuine innovation in the binding model for repeated patterns, and its significance becomes apparent only when combined with the index-variable mechanism.
In a collection-based model, the values bound across repetitions form an ordered sequence — [v1, v2, v3, ...]. Accessing the "previous" value requires computing length(collection) - 1 or similar, and accessing an arbitrary previous value (e.g., the third iteration's value when you're on the fifth iteration) requires knowing that the third iteration's value is at index 2. This is tractable but brittle: the binding order is tied to the expansion order, which in loop patterns with flexible ellipsis placement might not correspond to a simple left-to-right sequence.
The hash-table model decouples binding identity from expansion order. The key is the index expression evaluated at binding time — $x_i stores the value at key i, $x_(- i 1) stores it at key i-1, $a_(- i j) stores it at key i-j. This means:
-
Random access by semantic index, not positional offset. The n-queens inner loop references
a_jwherejranges from 1 toi-1— the hash table stores queen positions by row number, and any row can be looked up directly. In a collection-based model, the first queen would be at position 0, the second at position 1, etc., and the programmer would need to maintain this positional mapping manually. -
Sparse and non-sequential indices work naturally. The consecutive-integer pattern references
x_(- i 1)— the previous iteration's value, accessed by a key that is one less than the current index. In a collection-based model, this would becollection[length-2]or similar — fragile if the collection contains values from multiple nested loops. -
Multiple loop indices can coexist in the same hash. In the n-queens solver,
a_(- i j)produces keys likea_1,a_2, etc. — the same hash tableastores all queen positions regardless of which index expression produced the key.
The significance of this design choice is that it makes cross-iteration references a first-class, syntactically lightweight operation. The programmer writes x_(- i 1) to get the previous value — no length queries, no positional arithmetic. This is what enables the expressive patterns in Section 4.2 (consecutive integers, triangular lists) to be written as single declarative patterns rather than as patterns with explicit state-tracking.
The paper does not claim the hash-table model as a standalone contribution, but it is a necessary piece of the puzzle: the index variable would be much less useful if retrieving previously bound values required cumbersome positional bookkeeping. The hash-table model and the index variable together form the binding infrastructure that makes parameterization-by-repeat-count ergonomic, not merely possible.
5. Experimental Analysis
Evaluation Methodology
Dataset. The paper does not report experimental results on a standard benchmark dataset with quantitative performance metrics in the conventional sense. Instead, it presents working code examples that demonstrate the expressiveness and correctness of loop patterns on specific algorithmic problems. The "test cases" are individual problem instances — specific lists, trees, or graphs — against which the patterns are evaluated, with the expected results shown in program comments. The examples span four domains: combinatorics (combinations of elements from a list), constraint satisfaction (n-queens), tree traversal (ancestor enumeration), and graph search (shortest path, traveling salesman). There is no separate training/validation/test split, no held-out evaluation set, and no aggregation of performance across a corpus of problems. The paper's evaluation is entirely qualitative and demonstrative — it shows that certain patterns can be expressed and produce correct results, not that they achieve some quantitative performance metric.
Base model(s). The examples are implemented in the Egison programming language [1, 11], which provides the underlying pattern-matching infrastructure: user-customizable matchers for algebraic data types (via the matcher expression), non-linear patterns with backtracking, multiple-result semantics (the match-all expression), lazy evaluation, and indexed pattern variables. There is no "model" in the machine-learning sense — Egison is a programming language interpreter/compiler. The version used is not specified beyond the language name. The paper does not compare against other pattern-matching systems empirically (no execution on Mathematica, Racket, trx, or any graph query language).
Metrics. There are no quantitative metrics. The "evaluation" consists of showing that a pattern written using loop patterns, when executed against a specific input, produces the expected output collection. Correctness is demonstrated by the program comment showing the evaluation result: for example, ; {{1 2} {1 3} {2 3} {1 4} {2 4} {3 4}} for (comb2 {1 2 3 4}) (Section 4.1). The paper implicitly claims that the outputs are correct, verifiable by inspection against the problem specification. No metric of efficiency (runtime, memory, number of backtracking steps) is reported.
Baselines. The paper does not provide empirical baselines in the sense of running the same problems through alternative systems and comparing results. The baselines are conceptual: the paper argues that certain patterns cannot be expressed at all using classical repeated patterns (Mathematica's Repeated, Racket's extensible patterns) or regular-tree expressions (trx), making the baseline "inexpressible" rather than "slower" or "less accurate." The evidence for inexpressibility is by example: the paper presents patterns (the n-queens solver with parameterized n in Figure 3, the consecutive-integer pattern in Section 4.2, the tree ancestor traversal in Figure 4, the graph path patterns in Figures 5–6) and argues that these rely on either the index variable or the flexible ellipsis placement in ways that classical repeated patterns cannot replicate. There is no formal proof of inexpressibility — the argument is by construction and demonstration.
Generation budget / compute accounting. Not applicable. There is no notion of a generation budget, FLOPs, or compute measurement in this paper. The paper makes a brief remark about computational complexity in Section 6.2: "A loop pattern is expanded only when it is necessary. Therefore, the time complexity of pattern matching using loop patterns is completely same with pattern matching written not using them." This is a claim of zero overhead — loop patterns are expanded on-demand to the same matching atoms that a hand-written non-loop pattern would contain — but no timing measurements, complexity analyses, or scaling experiments support this claim.
Cross-validation / statistical protocol. Not applicable. There is no statistical methodology, no cross-validation, no confidence intervals, and no aggregation across multiple problem instances. Each example is a single program evaluated on a single input (or a small finite collection of inputs, as in comb2 and comb3). The correctness of the pattern is established by the programmer inspecting the output and verifying it against the problem specification — not by an automated evaluation harness.
Main Qualitative Results
Since the paper presents no quantitative results, this section describes the demonstrated capabilities organized by problem domain, treating each code example as a "result" that shows a specific pattern is expressible with loop patterns and produces the expected output.
Combinatorics: Parameterized Element Selection
The combination examples in Section 4.1 demonstrate the most basic capability of loop patterns: parameterizing the number of elements to extract from a collection.
comb2 (non-loop version): The fixed version (Section 4.1, first code block) uses a hardcoded pattern <join _ <cons $x_1 <join _ <cons $x_2 _>>>> to extract exactly two elements. It produces all unordered pairs from {1 2 3 4}: {{1 2} {1 3} {2 3} {1 4} {2 4} {3 4}}. This is the correct output for choose-2 from a 4-element set (6 pairs = 4 choose 2).
comb3 (non-loop version): The three-element version simply nests one more level: <join _ <cons $x_1 <join _ <cons $x_2 <join _ <cons $x_3 _>>>>>>. It produces all 4 triples ({{1 2 3} {1 2 4} {1 3 4} {2 3 4}}), which is 4 choose 3 = 4 — correct.
comb (loop version): The generalized version (comb n xs) uses (loop $i [1 {n} _] <join _ <cons $x_i ...>> _) and produces the same results for n=2 and n=3 as the hardcoded versions — correctness by equivalence. For n=2 with input {1 2 3 4}, the output is the same 6 pairs; for n=3, the same 4 triples. The key demonstration is that a single pattern replaces two (and by extension, all n) hardcoded patterns. The loop pattern's index variable $i parameterizes the number of repetitions, and the end numbers {n} tell the system when to stop.
comb2or3 (branching end numbers): This example (Section 4.1) uses (loop $i [1 {2 3} $n] <join _ <cons $x_i ...>> _) to produce both 2-element and 3-element combinations from a single pattern. The output {{1 2} {1 3} {2 3} {1 4} {2 4} {3 4} {1 2 3} {1 2 4} {1 3 4} {2 3 4}} is exactly the union of the comb2 and comb3 outputs — 6 pairs + 4 triples = 10 results. The end-number pattern $n captures whether the match used 2 or 3 iterations, and the body expression (map (lambda [$i] x_i) (between 1 n)) collects the appropriate number of elements. This demonstrates that a single loop pattern can produce results at multiple iteration counts — a capability not present in classical repeated patterns, which have a single (possibly zero-or-more) repetition count but cannot produce results at intermediate counts.
Constraint Satisfaction: The n-Queens Solver
The n-queens examples (Section 5.1, Figures 2–3) are the paper's most complex demonstration and directly illustrate the necessity of both the index variable and cross-iteration value references.
Four-queens (non-loop version, Figure 2): The hardcoded pattern for four queens explicitly writes out the constraints for all four positions:
<cons $a_1
<cons (& !,(- a_1 1) !,(+ a_1 1) $a_2)
<cons (& !,(- a_1 2) !,(+ a_1 2) !,(- a_2 1) !,(+ a_2 1) $a_3)
<cons (& !,(- a_1 3) !,(+ a_1 3) !,(- a_2 2) !,(+ a_2 2) !,(- a_3 1) !,(+ a_3 1) $a_4)
<nil>>>>>
The input is {1 2 3 4} matched as a multiset integer. The pattern uses cons to select queens one by one, with each new queen's position constrained against all previous queens' positions via not-patterns checking diagonal attacks. The output is {{2 4 1 3} {3 1 4 2}} — the two valid solutions to the 4-queens problem. This is correct (there are exactly two solutions for n=4, up to symmetries).
n-queens (loop version, Figure 3): The generalized version uses a nested double loop pattern:
<cons $a_1
(loop $i [2 n]
<cons (loop $j [1 (- i 1)]
(& !,(- a_j (- i j)) !,(+ a_j (- i j)) ...)
$a_i)
...>
<nil>)>
For (n-queens 4), the output is the same two solutions as the hardcoded version — correctness by equivalence. The paper shows this output explicitly: {{|[1 2] [2 4] [3 1] [4 3]|} {|[1 3] [2 1] [3 4] [4 2]|}} (the pipe notation is the hash-table representation of a with keys 1–4 and values showing queen positions). The key demonstrations:
-
The outer loop's index variable
$iis referenced in the inner loop's end numbers[1 (- i 1)]. This means the inner loop checks constraints against exactlyi-1previous queens — the number of constraints grows with the current queen index. This is impossible with classical repeated patterns because the repeat count of one pattern cannot depend on the current count of another. -
The inner loop's repeat pattern references values from the outer and inner loops simultaneously:
a_jrefers to a previously placed queen (j < i), and(- i j)computes the row difference for the diagonal constraint. This requires cross-iteration value references — the inner loop's current iteration must access bindings from the outer loop (i) and from previous inner-loop iterations (a_j). The hash-table binding model makes this straightforward:a_jlooks up the value at keyjin the hasha. -
The pattern uses an and-pattern
(& ... $a_i)as an as-pattern: the not-patterns check diagonal constraints while$a_isimultaneously binds the current queen's position. This composition of loop patterns with non-linear constraints, and-patterns, and not-patterns is what makes the solver declarative — the programmer specifies what a valid solution looks like, not how to search for it.
The paper claims: "This pattern is an example that can be described only by the loop patterns" — a claim supported by the observation that both the index-dependent end numbers and the cross-iteration value references are necessary for the generalization, and neither is available in classical repeated patterns.
Tree Traversal: Ancestor Enumeration
The tree example (Section 5.2, Figure 4) demonstrates that loop patterns can express patterns for non-list data structures — the second claimed limitation of classical repeated patterns.
Data definition. A tree is defined with two constructors: leaf (takes a string) and node (takes a string and a multiset of trees). The example tree-data encodes a category hierarchy for programming languages, where "Egison" appears under both "Pattern-matching-oriented" and "Functional language / Dynamically typed."
The pattern:
(loop $i [1 $n]
<node $c_i <cons ... _>>
<leaf ,"Egison">)
This pattern searches for a leaf containing "Egison" and enumerates all ancestors by traversing upward through node constructors. The repeat pattern <node $c_i <cons ... _>> matches a node, binds its category name to $c_i, and places the ellipsis inside the cons within the node's children — meaning the next expansion will look for the parent of this node. The end pattern <leaf ,"Egison"> represents the base case: a leaf node whose value is "Egison."
Output: The match-all expression returns two results, corresponding to the two paths from "Egison" to the root in the category tree:
{[1 "Programming language"] [2 "Pattern-matching-oriented"]}(the path through the Pattern-matching-oriented category){[1 "Programming language"] [2 "Functional language"] [3 "Dynamically typed"]}(the path through the Functional language / Dynamically typed categories)
The output is a hash mapping position indices to category names, showing the ancestors in order from the root downward. The paper's comment says "All categories that Egison belongs" — these are the two paths through the hierarchy.
This example demonstrates:
-
The ellipsis is placed inside a
nodeconstructor, not at the tail of a list. The repeat pattern wraps "upward" through the tree hierarchy — each expansion moves one level closer to the root. This is structurally impossible with classical repeated patterns, which only append to the tail of sequences. -
The same loop pattern expresses variable-length paths. The first result has 2 nodes (2 ancestors), the second has 3 nodes — the loop automatically matches the correct depth for each path. The end-number pattern
$ncaptures the path length, and the body retrieves the appropriate number of categories. -
The pattern uses only simple constructors (
node,leaf,cons) plus the loop pattern. The paper explicitly contrasts this with XML path languages [7], which "use the built-in ancestor command to enumerate all ancestors of a node." The loop pattern achieves the same expressiveness without a built-in ancestor primitive — it composes generic pattern constructors with a general-purpose repetition mechanism.
Graph Pattern Matching: Shortest Path and Traveling Salesman
The graph examples (Section 5.3, Figures 5–6) are the most ambitious demonstrations, showing that loop patterns can express sophisticated graph queries typically requiring domain-specific query languages.
Graph as a set of edges (Figure 5). A directed graph is represented as a set of edge constructors, each containing source and target node integers. graph-data defines a 5-node graph with edges: 1→4, 2→1, 3→1, 3→2, 4→3, 5→1, 5→4.
The shortest-path pattern:
(let {[$x_1 s]}
(loop $i [2 $n]
<cons <edge ,x_(- i 1) $x_i> ...>
<cons <edge ,x_(- n 1) (& ,e $x_n)> _>))
This pattern finds all paths from node s (bound to 1 in the let-pattern) to node e (bound to 2). The repeat pattern <cons <edge ,x_(- i 1) $x_i> ...> matches an edge from the previous node x_(- i 1) to a new node x_i, with the ellipsis indicating that more edges follow. The end pattern <cons <edge ,x_(- n 1) (& ,e $x_n)> _> matches the final edge that reaches the target node e, using an and-pattern to verify the target while binding it to x_n. The car (first element) of the result collection is taken, giving the shortest path (since shorter paths correspond to smaller n, and lazy evaluation produces results in order of increasing complexity).
Output: {1 4 3 2} — the path 1→4→3→2. This is indeed one of the shortest paths from 1 to 2 in the given graph (the direct edge 2→1 exists but goes the wrong direction; the path 1→4→3→2 has 3 edges, which is minimal given that there is no 1→2 edge).
This example demonstrates:
-
Cross-iteration value references are essential. The pattern refers to
x_(- i 1)— the node reached in the previous edge — to constrain the next edge's source. This chains edges into a continuous path. Classical repeated patterns cannot express this chaining because each repetition is independent. -
The let-pattern handles the initial case cleanly. The first node
x_1is bound by the let-pattern before the loop begins, so the loop's first iteration (withi=2) can referencex_(- i 1)=x_1without special-casing the first edge. -
Shortest-path is obtained for free from lazy evaluation + multi-result semantics. The
match-allexplores all paths, andcarreturns the first one — which, by construction (shorter paths use smallern), is the shortest. The programmer did not need to write a shortest-path algorithm; the declarative pattern specification combined with the evaluation strategy produces it.
Graph as an adjacency list (Figure 6). A different graph representation: each node is a pair of a station name and a multiset of (destination, price) pairs. graph-data represents Tokyo's railway network with stations and fares. The traveling-salesman pattern:
<cons [,"Tokyo" <cons [$s_1 $p_1] _>]
(loop $i [2 5]
<cons [,s_(- i 1) <cons [$s_i $p_i] _>]
...>
<cons [,s_5 <cons [(& ,"Tokyo" $s_6) $p_6] _>]
_>)>
This pattern finds all routes that visit all five cities exactly once and return to Tokyo. The repeat pattern <cons [,s_(- i 1) <cons [$s_i $p_i] _>] ...> consumes one city visit: the source must be the previously visited city s_(- i 1), and a new city s_i is selected with fare p_i. The end pattern <cons [,s_5 <cons [(& ,"Tokyo" $s_6) $p_6] _>] _> matches the final leg returning to Tokyo, with the and-pattern verifying the destination is "Tokyo" (binding it to s_6) — the verification (& ,"Tokyo" $s_6) checks that the destination equals "Tokyo" while binding s_6 for the result.
Output: The body expression [(sum (map (lambda [$i] p_i) (between 1 6))) s] returns the total fare and the list of visited cities for each valid tour. The paper does not show the output explicitly in the commented result, but the correctness of the pattern logic is verifiable by inspection: it matches a cycle through all five intermediate cities returning to Tokyo, with the constraint that the i-th city is adjacent to the (i-1)-th city in the graph.
This example is specifically identified by the paper (Section 5.3) as "an example that can be described only by the loop patterns because it refers to the value bound in the previously repeated pattern as ,s_(- i 1)." This is the same cross-iteration reference capability as in the shortest-path example, applied to a different graph representation.
Ablation Studies and Robustness Checks
The paper includes no ablation studies or robustness checks in the conventional empirical sense. There are no experiments varying hyperparameters, no comparisons of alternative design choices with quantitative metrics, and no sensitivity analyses. However, the paper does contain design-choice discussions that serve a function analogous to ablations — they examine what happens when a particular component of the design is removed or changed, and argue for the presented design. These are not experiments but thought-experiments backed by code examples.
Value-pattern-only termination vs. explicit end numbers (Section 6.1): This is the closest the paper comes to an ablation. The proposed alternative is to replace [1 {(- i 1)} _] (explicit end numbers with wildcard end pattern) with [1 ,(- i 1)] (value-pattern-based termination, no explicit end numbers). The paper identifies a concrete failure mode: in the n-queens inner loop, the value-pattern-only version would cause the system to try j = i (beyond the intended bound i-1), which would reference the unbound variable a_i, causing a runtime error. This is a "negative result" ablation — the simpler design fails in a specific, reproducible way. The explicit end numbers mechanism is justified as necessary for correctness, not as a performance optimization.
Index variable removed: An implicit ablation (not discussed explicitly but inferable). What if the loop pattern had no named index variable and used an implicit count (like classical repeated patterns)? The paper's examples that require the index — the inner loop's end numbers [1 (- i 1)] in the n-queens solver, the value pattern ,(+ 1 x_(- i 1)) in the consecutive-integer pattern, the indexed variable $x_i in the combination examples — would be inexpressible. The paper demonstrates this implicitly by showing patterns that use the index variable in essential ways; removing it would collapse the expressiveness back to classical repeated patterns.
Hash-table vs. collection storage for repeated bindings (Section 4.2): The paper contrasts its hash-table-based indexed variables with Mathematica and Racket's collection-based approach. No side-by-side experiment is performed, but the paper argues through its examples that the hash-table model enables patterns (like ,s_(- i 1) in the graph examples and a_j in the n-queens inner loop) that would be more cumbersome or impossible with sequential collection storage. This is a design-level ablation: change the binding model and certain patterns become inexpressible.
No loop pattern at all (implicit ablation): The comparison between the four-queens solver (Figure 2, hardcoded) and the n-queens solver (Figure 3, loop-based) serves as an implicit ablation: without loop patterns, the programmer must hardcode each value of n (the paper shows n=4; to support n=5 would require writing a different pattern). With loop patterns, a single parameterized pattern handles all n. The "ablation" result is that expressiveness collapses from parameterized to fixed-n.
Critical Assessment
What Was Demonstrated vs. What Was Claimed
The paper's central claims must be evaluated against what the experiments (examples) actually demonstrate, not what they are asserted to demonstrate.
Claim from Section 1: Loop patterns overcome the two limitations of classical repeated patterns.
-
Limitation 1 (cannot change pattern content depending on repeat count): This is demonstrated convincingly. The n-queens solver (Figure 3) shows the inner loop's end number depending on the outer loop's index
(- i 1). The consecutive-integer pattern (Section 4.2) shows the pattern,(+ 1 x_(- i 1))constraining each element to be one more than the previous. The traveling-salesman pattern (Figure 6) shows each edge's source constrained to be the previous edge's destination via,s_(- i 1). These are patterns that genuinely could not be written with classical repeated patterns, which provide no mechanism for one repetition to reference bindings from another or for the repeated sub-pattern to vary with the count.However, the demonstration is qualitative, not quantitative. The paper does not systematically catalogue which classes of count-dependent patterns are expressible and which are not. It provides existence proofs — specific patterns that work — but no characterization of the expressiveness boundary. A skeptical reader might ask: are there count-dependent patterns that loop patterns still cannot express? The paper does not address this.
-
Limitation 2 (can only apply to lists): This is demonstrated through the tree example (Figure 4, ancestor traversal) and graph examples (Figures 5–6). The ellipsis is placed inside
nodeandconsconstructors at positions that are not the tail of a list — the tree example places it inside anode's children, and the graph examples place it inside edges within a collection. These patterns are structurally impossible with classical repeated patterns, which always append to the tail.However, there is a subtle point about what "arbitrary data structures" means. The paper claims loop patterns can be applied to "arbitrary data structures such as trees and graphs other than lists" (Section 1). The examples demonstrate trees and a specific graph encoding (edge sets, adjacency lists). They do not demonstrate pattern matching against arbitrary graph topologies with cycles (the shortest-path example's graph contains cycles, but the pattern is designed to find simple paths — it is not shown matching the entire graph structure, just extracting paths). The paper does not show loop patterns being used to match, say, a subgraph isomorphism pattern or a pattern that traverses a graph with labeled edges in both directions. The claim of "arbitrary" data structures is stronger than what is demonstrated.
Claim from Section 4.2: Loop patterns can represent patterns "that can be described only by the loop patterns."
This claim is, strictly speaking, unprovable by examples alone — it requires a proof of inexpressibility in the comparison systems, which the paper does not provide. What the paper actually demonstrates is that the specific patterns shown (n-queens, consecutive integers, tree ancestors, graph paths) use mechanisms (index variable, ellipsis placement, hash-table cross-iteration references) that classical repeated patterns and regular-tree expressions lack. This is compelling evidence but falls short of a formal inexpressibility result.
The comparison with trx [6] is particularly important because trx does handle trees. The paper claims trx "still suffer from the first limitation" because "recursively defined patterns do not provide a method for managing the repeat count" (Section 2). This is an empirical claim about trx's capabilities — it would be strengthened by attempting to encode one of the count-dependent patterns (e.g., the n-queens pattern) in trx and showing that it fails or requires circumvention. The paper does not do this.
Claim from Section 5.3: Our language can "represent various patterns by combining the loop patterns and a small number of simple pattern constructors" (contrasted with domain-specific query languages).
The examples support this claim qualitatively: the ancestor traversal (which would use a built-in ancestor command in XPath) is expressed using node, leaf, cons, and a loop pattern. The shortest path (which would use built-in path-finding in Cypher or Gremlin) is expressed using edge, cons, and a loop pattern. This demonstrates that loop patterns plus generic constructors can subsume some functionality that domain-specific languages provide through built-ins.
However, the paper does not demonstrate that loop patterns can express the full range of queries available in those languages. XPath has axes (ancestor, descendant, following-sibling, etc.), predicates, and functions. Cypher has variable-length relationships, shortest-path built-ins, and aggregations. The paper shows a few selected queries but does not attempt a systematic comparison. The claim that the approach can replace these languages' built-in functions is aspirational, not demonstrated.
Genuine Weaknesses in the Experimental Approach
No quantitative evaluation of any kind. This is the most significant weakness. The paper provides no measurements of:
- Correctness rate: How many patterns were tested against how many inputs? Were there any patterns that produced unexpected or incorrect results? The paper shows only successful examples — there are no negative results where a pattern failed or produced wrong output.
- Runtime performance: How long does pattern matching take for problems of different sizes? Does the n-queens solver's runtime scale reasonably with n? Is the overhead from loop-pattern expansion measurable compared to hand-written patterns? The zero-overhead claim in Section 6.2 is asserted without evidence.
- Memory usage: Does the hash-table binding model have memory implications? For patterns with many iterations, does the accumulation of hash-table entries become a bottleneck?
- Comparison with alternatives: What is the runtime of the same problems solved using recursive functions in Egison (without loop patterns) vs. the loop-pattern versions? Is there a performance penalty for the declarative approach?
The absence of quantitative evaluation is partially understandable given that this is a language-design paper, not a systems paper. But the claims about efficiency ("the time complexity... is completely same") and expressiveness ("can be described only by") are quantitative or comparative in nature and are not supported by measurements.
No test on large or complex inputs. All examples use very small inputs: a 4-element list for combinations, a 4-queens problem (scaled to n in the parameterized version, but no output is shown for large n), a tree with 4 categories and ~15 leaves, a graph with 5 nodes and 7 edges, a railway network with 6 stations. The paper does not demonstrate that the patterns scale to realistic problem sizes — e.g., an 8-queens problem (92 solutions), a tree with hundreds of nodes, or a graph with thousands of edges. The computational complexity discussion in Section 6.2 references [11] but provides no new analysis specific to loop patterns.
No demonstration of error handling or edge cases. What happens when a loop pattern's end numbers are empty? When the start number is greater than all end numbers? When the index range specifies end numbers that the index never reaches? When an ellipsis appears outside any loop context? The paper does not explore these edge cases. The formal semantics (Figure 7) provides a precise specification, but the paper does not walk through how the rules handle malformed or degenerate inputs.
No comparison with writing the same algorithms without loop patterns. The paper does not show the alternative — how would one write the n-queens solver, tree ancestor enumeration, or shortest-path search in Egison using recursive functions instead of loop patterns? Showing side-by-side comparisons would strengthen the expressiveness argument by making the conciseness gain quantifiable (lines of code, number of auxiliary functions) and would reveal whether loop patterns genuinely enable new algorithms or merely provide a more concise notation for existing ones.
All examples are from the paper's author. There is no evidence that other programmers can successfully use loop patterns to solve novel problems. The examples are carefully chosen to showcase the construct's strengths. A more convincing demonstration would include patterns contributed by users who learned the construct and applied it to problems not anticipated by the designer.
The "working" examples are not independently verified. The paper presents evaluation results as comments in the code — e.g., ; {{2 4 1 3} {3 1 4 2}} — but there is no automated test harness, no regression suite, and no independent confirmation that these outputs are correct. The reader must either trust the author or manually verify each output against the problem specification.
Missing Experiments That Would Have Strengthened the Paper
-
Encoding classical repeated patterns as loop patterns: The paper claims loop patterns "overcome the limitations" of repeated patterns but does not show that loop patterns can express everything that classical repeated patterns can. A demonstration that
(loop $i [0 (from 0) _] <cons $x_i ...> <nil>)subsumes the Kleene star for lists would establish that loop patterns are a genuine generalization, not just a different construct with different capabilities. -
Comparison with
trxon a shared problem: Sincetrxis identified as the closest prior work that addresses Limitation 2 (but not Limitation 1), a direct comparison on a tree-traversal problem would be informative. For example: encode the same tree data intrx, attempt to write the ancestor-enumeration pattern, and show whether it succeeds or fails. This would make the inexpressibility claim concrete rather than asserted. -
Scalability measurements: Run the n-queens solver for n from 4 to 12, measuring runtime and the number of backtracking steps. Compare against a recursive-function implementation. Show whether the loop-pattern version's performance degrades gracefully or hits a computational cliff.
-
Correctness on a benchmark suite: For the n-queens problem, verify the output for n=4 through n=8 against known solution counts (2, 10, 4, 40, 92 solutions respectively). For the traveling-salesman example, verify the minimum fare against a known ground truth. This would provide confidence that the patterns are not just "working" on the shown examples but are algorithmically correct.
-
Demonstration of error messages for malformed patterns: Show what happens when a programmer makes a mistake — e.g., uses an index variable that was not declared, places an ellipsis outside a loop, or specifies end numbers that are not in sorted order. Good error messages are a crucial part of language usability, and their absence leaves the reader uncertain about the debugging experience.
Conditional Nature of Claims
The paper's claims about expressiveness hold under specific conditions that are not always made explicit:
-
The claim that loop patterns express patterns "that can be described only by the loop patterns" holds only if we accept the paper's characterization of what classical repeated patterns and
trxcan do, which is based on conceptual analysis rather than formal proof or empirical comparison. A determined programmer might encode some of these patterns using recursive functions or macros in existing systems — the paper does not rule this out. -
The claim that loop patterns overcome Limitation 2 (apply to arbitrary data structures) holds for the specific data structures shown (algebraic trees, edge-set graphs, adjacency-list graphs) and the specific traversal directions demonstrated (upward through tree parents, forward along graph edges). It has not been demonstrated for cyclic graphs with bidirectional traversal, for graphs with edge labels that constrain the pattern, or for data structures with multiple simultaneous traversals (e.g., zipping two trees). The term "arbitrary data structures" overstates what has been demonstrated.
-
The zero-overhead claim in Section 6.2 ("completely same with pattern matching written not using them") is contingent on the implementation correctly expanding loop patterns to matching atoms without introducing additional search paths or overhead. No empirical evidence supports this, and the formal semantics (Figure 7) shows that loop patterns introduce branching (Rules 3–4) that may or may not be equivalent to hand-expanded patterns — the equivalence is not proven.
-
The claim that the language can replace domain-specific query languages (Section 5.3, Section 8) is aspirational and conditional on future work. The paper shows a few selected queries but does not demonstrate coverage of the full query capabilities of XPath, Cypher, or SPARQL.
6. Limitations and Trade-offs
6.1 No Quantitative Evaluation of Correctness, Performance, or Scalability
The assumption or constraint. The paper presents loop patterns as a working language feature and demonstrates their expressiveness through code examples with expected outputs shown in comments. However, it includes no systematic evaluation of the construct along any quantitative dimension: correctness on a test suite, runtime performance, memory usage, or scaling behavior with problem size. The paper's entire empirical case rests on approximately 10–15 hand-selected code examples evaluated on very small inputs (4-element lists, 5-node graphs, 4×4 chessboards). The paper acknowledges none of this as a limitation.
The consequence. The reader cannot assess whether loop patterns are practically usable beyond the demonstrated toy examples. Several specific concerns arise:
-
Correctness uncertainty. The paper shows outputs for specific inputs (e.g.,
{{2 4 1 3} {3 1 4 2}}for the 4-queens solver in Figure 3) but never verifies correctness systematically. For the n-queens problem, the known solution counts for n=4 through n=8 are 2, 10, 4, 40, and 92. The paper does not confirm that the loop-pattern-based n-queens solver produces the correct count for any n beyond 4. For the traveling-salesman example (Figure 6), no output is shown at all — the reader cannot verify the pattern produces correct tours. -
Performance opacity. The paper claims in Section 6.2 that "the time complexity of pattern matching using loop patterns is completely same with pattern matching written not using them," but provides no timing data, no asymptotic analysis of the loop-pattern expansion rules (Figure 7), and no comparison of loop-pattern-based solutions against equivalent recursive-function implementations. The formal semantics in Figure 7 show that Rules 3–4 introduce branching (exploring both termination and continuation at intermediate end numbers), which may create additional backtracking paths not present in hand-expanded patterns. Whether this branching is computationally equivalent to what a programmer would write manually is asserted, not proven.
-
Scaling ignorance. All inputs are trivially small. The n-queens solver is shown for n=4 but the parameterized version claims to work for arbitrary n — does it complete in reasonable time for n=8 (92 solutions, 8! = 40,320 permutations to search)? For n=12? The graph examples use 5–6 nodes — what happens with a graph of 1000 edges? The tree example uses a 15-leaf hierarchy — what happens with thousands of nodes and deep nesting? The paper provides no scaling data to bound expectations.
Evidence in the paper. None — this limitation is defined by the absence of evaluation. Section 5 is titled "Examples" and consists entirely of code demonstrations with manually annotated expected outputs. There is no section on performance, benchmarking, or correctness validation. The only comment on computational complexity is the unsubstantiated claim in Section 6.2, which references [11] for the base pattern-matching system's complexity but adds no analysis specific to loop patterns.
Mitigation status. Not addressed. The paper does not acknowledge the absence of quantitative evaluation as a limitation. Section 8 mentions future work on "an efficient execution method of our pattern-matching system and the loop patterns" for integration with query languages, but this concerns optimization for specific domains, not basic performance characterization of the construct as presented. A practitioner deciding whether to adopt loop patterns has no empirical basis for predicting runtime, memory, or correctness on realistic inputs.
6.2 The Difficulty Estimation Cost Is Unaccounted for — and the Analogue Is the Cost of Programming Loop Patterns Correctly
The assumption or constraint. While this paper does not use machine-learning-style "difficulty estimation" (it is a language-design paper, not an ML paper), there is an analogous hidden cost that affects practical adoption: the intellectual and debugging burden on the programmer to correctly specify the index range and ellipsis placement. The paper assumes that the programmer can correctly determine the start number, end numbers, end-number pattern, repeat pattern, and end pattern for a given problem, and that the interaction of these components with backtracking, non-linear constraints, and lazy evaluation will produce the intended behavior. The paper's examples were constructed by the language designer — there is no evidence that other programmers can do so without extensive trial and error.
The consequence. Several aspects of loop-pattern programming impose cognitive costs that are not accounted for in the paper's expressiveness claims:
-
The end-number specification is non-trivial to get right. Section 4.1 explains that end numbers must be a "sorted list of integers" known before pattern matching begins. But what should the list contain? For
comb2or3, it must be{2 3}— specifying{3 2}(unsorted) or{2 4}(including an unreachable end number) would likely produce incorrect behavior. For the n-queens inner loop (Figure 3), it is[1 (- i 1)]— the programmer must correctly computei-1as the termination bound, and must understand that this expression is evaluated in an environment where the outer loop's$iis bound. For the tree ancestor traversal (Figure 4), the end numbers are(from 1)— an infinite sequence — which requires understanding that lazy evaluation and the end pattern<leaf ,"Egison">will terminate the loop when the target leaf is found, not when the index reaches a predefined bound. These are not obvious choices; they require understanding the interplay between end numbers, the end pattern, and the target data. -
The ellipsis placement determines traversal direction, and incorrect placement produces patterns that match nothing or match incorrectly, possibly without clear error messages. In the tree example (Figure 4), the ellipsis is placed inside
<cons ... _>inside<node $c_i ...>— this means "move up one level in the tree." Placing the ellipsis before thenodeconstructor or after theconswould produce a pattern with completely different (and likely unintended) semantics. The paper provides no guidance on how to debug such errors or how to reason about correct ellipsis placement. -
The interaction with non-linear patterns and backtracking can produce unexpected results. The n-queens solver (Figure 3) relies on non-linear constraints (
!,(- a_j (- i j))) inside the inner loop's repeat pattern. If the programmer mis-specifies the index arithmetic (e.g., writing(- j i)instead of(- i j)), the pattern will compile and run but produce incorrect results — the two solutions shown for 4-queens might vanish or incorrect solutions might appear. The paper provides no testing methodology or debugging strategy. -
There is no demonstrated methodology for constructing loop patterns from problem specifications. Each example is presented as a finished product; the paper does not walk through the design process, does not show intermediate attempts that failed, and does not articulate general principles for translating a problem into the correct choice of start number, end numbers, repeat pattern, end pattern, and ellipsis placement.
Evidence in the paper. The paper's own discussion in Section 6.1 provides indirect evidence of this difficulty. The end-number mechanism exists specifically because a seemingly simpler design (value-pattern-only termination) causes runtime errors in certain cases. The fact that the language designer identified this pitfall and added a non-obvious mechanism (explicit end numbers) to prevent it suggests that the design space is subtle and that programmers attempting to use value patterns for termination (a natural intuition) would encounter confusing failures. The paper does not discuss whether the current design has analogous subtle failure modes.
The paper also acknowledges in Section 8 that "the semantics of the loop patterns presented in this paper is a bit complicated as a built-in language feature" and suggests "research for finding simpler language constructs for constructing the loop patterns is also interesting." This is a concession that the current design imposes a complexity burden, but the paper does not discuss the practical consequence: programmer errors.
Mitigation status. Partially acknowledged but not addressed. The paper's suggestion of future research into simpler constructs acknowledges the complexity but offers no immediate mitigation — no debugging tools, no error-reporting discussion, no design patterns, no testing methodology. A practitioner adopting loop patterns today must learn the correct usage through trial and error on their own problems, without guidance from the paper on how to avoid the pitfalls that the end-number mechanism was designed to prevent.
6.3 Expressiveness Claims Are Supported by Existence Proofs, Not by Formal Characterization or Comparative Evaluation
The assumption or constraint. The paper makes strong claims about what loop patterns can express: they overcome the "limitations of the Kleene star operator and the repeated patterns" (Section 8), they can represent patterns "that can be described only by the loop patterns" (Section 5.1), and they enable description of "various patterns for various data types in a unified way with a small number of pattern constructors and the loop patterns" (Section 8). These claims are expressiveness claims — they assert that certain patterns are inexpressible in alternative systems and expressible with loop patterns. The paper supports these claims entirely through existence proofs: specific patterns are shown to work on specific inputs, and the paper argues conceptually that classical repeated patterns and trx cannot express them.
The consequence. Several critical questions are left unanswered:
-
What is the exact expressiveness boundary? The paper identifies two limitations (no count dependence, lists only) and shows patterns that overcome each. But does the loop pattern construct have its own inexpressiveness limitations? Are there patterns that a programmer might naturally want to write but that the index-range/ellipsis mechanism cannot express? For example, the paper does not show loop patterns expressing: (a) a pattern where the repeat count depends on the data matched in an early iteration (e.g., "match exactly as many elements as the value of the first element"), (b) simultaneous traversal of two independent data structures with different iteration rates, (c) patterns with conditional repetition where the choice of which sub-pattern repeats depends on the data matched at runtime. Without a characterization of the expressiveness boundary, the reader cannot assess whether loop patterns are sufficient for their application or whether they will encounter new inexpressibility barriers.
-
Is the claimed advantage over
trxreal? The paper states (Section 2) thattrx's recursively defined patterns "still suffer from the first limitation" because they "do not provide a method for managing the repeat count." This is a conceptual argument, not an empirical finding — the paper does not attempt to encode a count-dependent pattern (e.g., the n-queens pattern) intrxand show that it fails. A skeptical reader might wonder whether a skilledtrxprogrammer could use the language's other features (recursive functions, explicit state threading) to achieve equivalent functionality, albeit less concisely. The inexpressibility claim is asserted, not demonstrated. -
Is the loop pattern construct sufficient to express all patterns that classical repeated patterns can? The paper claims loop patterns are an "extension" (Section 1) but does not demonstrate that they subsume the Kleene star — i.e., that every pattern expressible with classical repeated patterns has a natural encoding as a loop pattern. While this is likely true (a loop pattern with a fixed repeat pattern and tail-placed ellipsis should encode the Kleene star), demonstrating the encoding would establish that loop patterns are a genuine generalization rather than an alternative with different trade-offs.
-
How does conciseness compare quantitatively? The paper's expressiveness argument implies conciseness — a single loop pattern replaces multiple hardcoded patterns (the n-queens generalization) or replaces recursive functions with manual state management (the tree and graph traversals). But the paper never quantifies this: lines of code, number of auxiliary definitions, cyclomatic complexity. The four-queens solver (Figure 2) is ~12 lines of pattern code; the n-queens solver (Figure 3) is ~10 lines — the conciseness gain for parameterization is modest in this case. The tree ancestor pattern (Figure 4) is ~5 lines of pattern code, but the paper does not show the equivalent recursive function, so the gain is unmeasured.
Evidence in the paper. The paper's evidence is entirely by demonstration. Section 4.2 shows two patterns (the triangular-list check and the consecutive-integer check) and asserts that they depend on the index variable and hash-table binding model. Section 5.1 asserts the n-queens pattern "can be described only by the loop patterns." Section 5.3 asserts the traveling-salesman pattern is "an example that can be described only by the loop patterns." These are qualitative claims backed by code examples, not by formal inexpressibility proofs or comparative implementation in alternative systems.
The paper's discussion of trx (Section 2) is a single paragraph with no code comparison. The discussion of Mathematica and Racket (Section 4.2) is a single sentence about their collection-based binding model. The reader is asked to accept the inexpressibility claims based on conceptual analysis, not empirical head-to-head comparison.
Mitigation status. Not addressed. The paper does not acknowledge the gap between existence-proof demonstrations and formal expressiveness characterization. Future work on integration with query languages (Section 8) might produce comparative implementations, but the paper does not frame expressiveness characterization as an open problem.
6.4 The Formal Semantics Are Specified but Key Properties Are Unproven
The assumption or constraint. Section 7 presents formal semantics for loop patterns as an extension of the base semantics from [11], with four highlighted rules added for loop-pattern creation, ellipsis expansion (non-terminal), ellipsis expansion (intermediate end number), and ellipsis expansion (final end number). The paper presents these rules as the specification of correct behavior, but it does not state or prove any properties about them.
The consequence. Without proven properties, implementers and users must trust that the semantics satisfy certain basic expectations. Several specific concerns arise:
-
Termination is not proven. The paper emphasizes the importance of explicit end numbers for preventing infinite expansion (Section 6.1), but the formal semantics in Figure 7 do not come with a termination proof. Under what conditions does a loop-pattern-containing pattern terminate? Consider a loop pattern with end numbers
(from 1)(the infinite sequence) and an end pattern that always fails (e.g., a value pattern,0when the index starts at 1 and only increases). The semantics would repeatedly hit Rule 2 (not at end number), incrementing the index forever without ever reaching the end pattern — non-termination. The paper does not characterize when termination is guaranteed, nor does it provide a termination checker or warning mechanism. -
Determinism and confluence are not discussed. The matching-state transition rules (Figure 7) use a non-deterministic choice at several points — for example, Rule 3 produces two alternative continuations (termination and continuation). The paper's backtracking semantics implies that both are explored, but the formal rules use
(some ...)to indicate non-deterministic choice without specifying an exploration order. Is the set of results independent of the exploration order? (It should be, formatch-all.) Does the order of results frommatch-allhave defined semantics (e.g., lazy evaluation producing shorter matches first)? These properties are not stated or proven. -
Type soundness is not addressed. The semantics in Figure 7 match patterns against values using matchers. What if the index range's end-number pattern (
p1in the loop context) is matched against the index value using thesomethingmatcher, but the programmer writes a pattern that expects a structured value rather than an integer? The paper does not discuss type errors or how the semantics handles them. -
Equivalence of loop patterns to their expansions is unproven. The paper claims in Section 6.2 that loop patterns have "completely same" time complexity as hand-expanded patterns. This claim implicitly assumes that the semantics of a loop pattern is equivalent to the semantics of its expansion — i.e., that replacing a loop pattern with its expanded form (as the ellipsis rules do step-by-step) preserves the set of successful matches. This is a semantic equivalence property that requires proof. The paper provides no such proof, nor does it state the property formally.
-
Interaction with the base semantics is specified but not verified. The loop-pattern rules are added to a base semantics from [11]. The paper does not discuss whether the extensions preserve any properties of the base system (e.g., whether the base pattern-matching rules continue to work identically when loop contexts are present on the stack, whether the introduction of loop contexts affects the matching of non-loop patterns that share the same matching-atom stack).
Evidence in the paper. Figure 7 presents the formal semantics. Section 6.2 provides an informal argument that loop-pattern expansion is costless. The paper does not claim to have proven any semantic properties, but neither does it acknowledge their absence as a limitation. This is an omission — formal semantics are presented as the definitive specification, but without proven properties, their value as a foundation for implementation and reasoning is diminished.
Mitigation status. Not addressed. The paper does not identify unproven semantic properties as a limitation or as future work. Section 8 suggests "research for finding simpler language constructs" but does not mention formal verification or property proofs for the current semantics.
6.5 Single-Programmer, Single-Language, Single-Problem-Domain Evaluation
The assumption or constraint. All examples in the paper are written by the paper's author (Satoshi Egi) in a single programming language (Egison) on a narrow set of problem domains: combinatorics (combinations), constraint satisfaction (n-queens), tree traversal (ancestor enumeration), and graph search (shortest paths, traveling salesman). The Egison language itself is developed by the same author ([1, 9, 10, 11]), meaning the designer of the loop pattern construct is also the implementer of the language, the writer of the examples, and the evaluator of the results. There is no external validation, no user study, and no demonstration of the construct being used by programmers other than its designer.
The consequence. Several threats to the validity and generalizability of the findings arise:
-
Designer bias in example selection. The examples are carefully chosen to showcase the construct's strengths. The paper does not report any failed attempts to encode patterns using loop patterns — patterns that the author initially thought would be expressible but turned out not to be. Without negative examples, the reader cannot assess whether the demonstrated expressiveness is representative or cherry-picked.
-
No evidence of learnability or usability. Can a programmer unfamiliar with the loop-pattern design learn to use it effectively? How long does it take? What are the common mistakes? The paper provides no data. The complexity acknowledged in Section 8 ("the semantics... is a bit complicated") hints that learnability may be a real concern, but it is not investigated.
-
Language coupling. All examples depend on Egison-specific features: the
match-allmulti-result semantics, non-linear patterns with backtracking, lazy evaluation, user-customizable matchers (algebraic-data-matcher,multiset,set,list), indexed pattern variables, let-patterns, and-patterns, not-patterns, value patterns, and thejoin/cons/nilpattern constructors for collections. It is unclear whether loop patterns would be equally expressive in a different language that lacks some of these features. The paper argues (Section 2) that loop patterns are "even more powerful when combined with" these features, but this also means the demonstrated expressiveness is partially attributable to the features being combined with, not to loop patterns alone. A language with loop patterns but without backtracking or non-linear patterns would not be able to express the n-queens solver as shown. -
Domain limitation. The paper's examples are drawn from algorithmically clean, well-specified problems with clear structural decompositions. The paper does not demonstrate loop patterns on messier, real-world pattern-matching tasks: parsing semi-structured log files, validating JSON against complex schemas with cross-field constraints, pattern matching against abstract syntax trees with variable binding (where scoping rules complicate traversal), or querying databases with joins and aggregations. The gap between the demonstrated domains and practical pattern-matching applications is not discussed.
-
No adversarial or stress-test examples. The paper does not show loop patterns applied to inputs designed to expose weaknesses — e.g., trees with cycles (when the matcher does not enforce acyclicity), graphs with self-loops, patterns where the end numbers are dynamically computed and might be empty, or deeply nested loop patterns with many iterations. The robustness of the implementation under stress is unknown.
Evidence in the paper. The acknowledgments section thanks Kentaro Honda for providing the n-queens solver program and Yuichi Nishiwaki for reviewing the formal semantics. This suggests some external feedback, but there is no indication that the loop-pattern construct was used independently by these individuals to solve novel problems. The examples in Section 5 are all attributed implicitly to the author. The paper does not reference any user community, any collection of user-contributed patterns, or any external evaluation.
Mitigation status. Not addressed as a limitation. The paper is presented as a language-design contribution with illustrative examples, not as an evaluated system. The absence of external validation is consistent with the norms of programming-language design papers (where the contribution is the construct and its semantics, not its empirical evaluation), but it limits the strength of the practical usability claims. Section 8 suggests future integration with query languages, which would involve external evaluation, but the paper does not identify the current single-programmer, single-domain evaluation as a limitation to be overcome.
6.6 No Discussion of Interaction with Existing Language Features: Scoping, Error Handling, and Debugging
The assumption or constraint. Loop patterns are proposed as an extension to an existing, complex pattern-matching system (Egison) with non-linear patterns, backtracking, lazy evaluation, and user-customizable matchers. The paper specifies the syntax and formal semantics of loop patterns in isolation, but it does not discuss how loop patterns interact with other language features in practice — particularly around scoping rules, error reporting, and debugging support.
The consequence. Several practical questions for implementers and users are left unanswered:
-
Scoping of the index variable. The index variable
$iin(loop $i [1 n] ...)is automatically bound and incremented by the system. What is its scope? The paper's examples show it being used in the repeat pattern, the end pattern, the end numbers of nested loops ([1 (- i 1)]in Figure 3), and value patterns (,(+ 1 x_(- i 1))in Section 4.2). But can it be shadowed by an outer pattern variable of the same name? What happens if a programmer writes(loop $i [1 n] (loop $i [1 m] ...))— do the two$ivariables conflict? The paper's formal semantics (Figure 7) uses a loop context stack that stores separate bindings per loop, but whether this prevents variable capture or enables it is not discussed. -
What happens when an ellipsis appears outside a loop context? The paper's grammar (Figure 1) defines
...as a pattern form usable in any pattern. The formal semantics (Figure 7) handles ellipsis by consulting the top loop context. What happens if an ellipsis is encountered when the loop context stack is empty? The rules in Figure 7 do not include a case for this — the premise of Rules 2–4 requires a loop context on the stack. If the stack is empty, no rule applies, which likely means the pattern matching fails (deadlock). Is this reported as an error? Does the system provide a helpful message ("ellipsis used outside a loop pattern") or does it silently fail? The paper does not say. -
What happens when end numbers are empty, unsorted, or contain values the index never reaches? The paper specifies that end numbers are a "sorted list of integers" (Section 4.1). What if the programmer provides
{3 2}(unsorted) or{}(empty) or{5}when the start number is 10 and the index only increases (never reaches 5)? The formal semantics do not specify error handling for these cases. The Rules 2–4 check whether the index equals the "first" end number — if the list is unsorted, "first" might not be the smallest, and the termination behavior could be incorrect. If the list is empty, no end number is ever equal to the index, and the loop never terminates (infinite expansion under Rule 2). The paper does not warn implementers or users about these edge cases. -
Debugging support. When a loop pattern fails to match as expected — producing too few results, too many results, or no results — how does the programmer diagnose the problem? The paper provides no discussion of error messages, tracing facilities, or debugging strategies. The backtracking semantics means that the system silently explores many alternatives; when none succeed, the programmer receives an empty collection with no indication of why the pattern failed. This is a general challenge for declarative pattern-matching systems, but loop patterns introduce additional failure modes (incorrect end numbers, misplaced ellipsis, index arithmetic errors) that compound the debugging difficulty.
-
Interaction with lazy evaluation. Egison uses lazy evaluation, which enables
match-allto handle infinite results. Loop patterns with end numbers(from 1)(infinite sequence) rely on lazy evaluation to avoid infinite expansion. But what happens when a programmer writes a loop pattern with infinite end numbers and an end pattern that never matches? The system attempts infinite expansion and never produces a result — but does it also never terminate? Can the programmer interrupt it? The paper does not discuss the practical experience of using loop patterns with lazy infinite structures.
Evidence in the paper. The formal semantics in Figure 7 specify the happy path — what happens when the loop context is well-formed and the end numbers are sorted and reachable. The paper does not include rules for error states, does not specify error messages, and does not discuss scoping beyond the formal binding of the index variable in the loop context. Section 6.1 discusses one edge case (value-pattern-only termination causing unbound variable errors) in the context of justifying the end-number mechanism, but this is presented as a design rationale, not as guidance for programmers on what errors to expect and how to handle them.
The paper's examples all use loop patterns in simple, correct configurations. There is no example of a malformed loop pattern and the resulting error. The reader has no model of how the system behaves when the programmer makes a mistake.
Mitigation status. Not addressed. The paper does not identify the absence of error-handling and debugging discussion as a limitation. Section 8's future work focuses on integration with query languages and simpler construct design, not on practical software-engineering concerns like error reporting and debugging. This is a significant gap for a construct as semantically complex as loop patterns — the cost of adoption includes not just learning the correct usage but also learning to diagnose incorrect usage, and the paper provides no support for the latter.
7. Implications and Future Directions
How This Work Changes the Landscape
This paper does not propose a new algorithm, a new optimization, or a new empirical finding. It proposes a new language construct — loop patterns — that extends the vocabulary of declarative pattern matching in a way that had not been achieved by prior constructs (repeated patterns, regular-tree expressions, or active patterns). The magnitude of the contribution is best characterized as a targeted generalization that opens a previously closed design space, rather than a paradigm shift. The paper's lasting value is in identifying and precisely characterizing two expressiveness bottlenecks that had been treated as separate problems by separate communities, and showing that they share a common solution.
The most significant conceptual shift the paper enables is the reunification of structural repetition and hierarchical traversal in a single pattern-matching abstraction. Prior to this work, a programmer needing to express "traverse the ancestors of a tree node" faced a choice: use a domain-specific language like XPath with its built-in ancestor axis, or abandon pattern matching and write a recursive function. Similarly, a programmer needing to express "the n-th list has n elements" had to either hardcode it for each n or write a recursive function with explicit length checks. These were not seen as related problems — the first was about data structure navigation, the second was about count-parameterized constraints. The paper's diagnostic insight — that both are consequences of the Kleene star coupling the expansion site to the tail position and hiding the repeat count — reframes them as two facets of the same missing expressive capability. This reframing is the paper's most durable contribution, independent of the specific syntax and semantics of loop patterns.
The paper also resolves, at least at the level of language design, a tension that had been implicit in the pattern-matching literature: can repeated patterns be both general (applicable to arbitrary data structures) and parameterized (varying with the repeat count)? The trx system [6] demonstrated that repeated patterns could be applied to trees, addressing the structural limitation, but did so without addressing the count-dependence limitation. The paper's analysis (Section 2) clarifies that solving one without the other still leaves real programs inexpressible — the n-queens solver and the traveling-salesman pattern require both simultaneously. This clarification shifts the research agenda from "extend repeated patterns to trees" (a solved problem in trx) to "design a repetition construct that simultaneously supports flexible placement, index exposure, and cross-iteration value references" — a harder but more complete specification that the paper partially fulfills.
The paper also changes the attractiveness of certain research directions in pattern-matching language design:
-
More attractive: combining generic repetition constructs with non-linear constraints. The paper's examples demonstrate that loop patterns derive much of their expressiveness from composition with Egison's non-linear patterns (the diagonal constraints in n-queens), backtracking with multiple results (the exhaustive search in graph path finding), and user-customizable matchers (the tree and graph data definitions). This suggests that the interaction between repetition and these other features is the fertile design space, not repetition in isolation. Future pattern-matching systems that support rich constraint specification (equality, inequality, arithmetic) alongside parameterized repetition will likely find more expressive power than systems that treat these features as separate modules.
-
Less attractive: adding more built-in traversal commands to domain-specific query languages. The paper argues (Section 5.2–5.3, Section 8) that a single general-purpose repetition construct combined with simple pattern constructors (
cons,join,node,edge) can subsume functionality that XPath, Cypher, and Gremlin provide through specialized built-in commands (ancestor, variable-length relationships,shortestPath). If this argument holds, it suggests that query-language designers should invest in making their pattern-matching core more general rather than adding more special-purpose query operators. The paper does not prove this — the coverage of query-language capabilities is limited to a few examples — but it provides a credible alternative design philosophy that challenges the built-in-command approach. -
Less attractive: treating repeated patterns as a solved, legacy feature. The paper implicitly argues that the Kleene star, as implemented in Mathematica, Racket, and parsing expression grammars, is a local optimum that does not generalize. Researchers who considered repeated patterns a mature, well-understood construct now have a concrete demonstration that fundamental expressiveness was left on the table. This may revive interest in repetition constructs as a research topic, particularly for languages targeting rich data structures (graphs, trees, tensors) rather than flat sequences.
Despite these shifts, the paper does not attempt a paradigm shift. It does not claim that loop patterns are the final answer, and it explicitly acknowledges (Section 8) that the semantics are "a bit complicated as a built-in language feature" and that "research for finding simpler language constructs... is also interesting." The paper's stance is that it has identified a genuine expressiveness gap and proposed a working construct to fill it, while leaving open the question of whether a simpler or more elegant construct could achieve the same expressiveness. This intellectual honesty strengthens the contribution by framing loop patterns as a proof of concept for a class of constructs rather than as the definitive solution.
Follow-Up Research This Work Enables
Formal characterization of the expressiveness boundary: exactly which count-dependent patterns are inexpressible with classical repeated patterns, and which remain inexpressible with loop patterns? The paper provides existence proofs — specific patterns that loop patterns can express and that (the paper argues) classical repeated patterns cannot — but does not characterize the expressiveness classes. A strong follow-up would formalize the pattern-matching capabilities of three systems (classical repeated patterns, trx-style recursively defined patterns, and Egison loop patterns) and prove inclusion or separation results. For example: can loop patterns express all patterns where the repeat count is a function of previously matched values (e.g., "match exactly n elements where n is the value of the first element")? Can they express patterns where the repeated sub-pattern alternates between two forms based on whether the index is even or odd? Can they express patterns where the repetition structure itself depends on runtime data (e.g., "match a binary tree encoded as nested lists, where the nesting depth is determined by the tree structure, not by a fixed count")? A formal language of "pattern schemas" parameterized by an integer n, with precise definitions of which schemas are realizable in each system, would elevate the paper's informal inexpressibility claims to rigorous results.
Implementation and empirical evaluation of loop patterns in a non-Egison setting, decoupling the construct from Egison-specific features. The paper's examples rely heavily on Egison's unique combination of features: non-linear patterns with backtracking, lazy evaluation, match-all multi-result semantics, user-customizable matchers, indexed pattern variables with hash-table storage, and-patterns as as-patterns, and let-patterns. It is unclear how much of the demonstrated expressiveness comes from loop patterns per se versus from these interacting features. A strong follow-up would implement a minimal loop-pattern system in a simpler host language — say, a subset of Racket's match with only linear patterns, strict evaluation, and first-match semantics — and systematically determine which of the paper's examples still work and which require the full Egison feature set. The hypothesis (suggested by the paper's own statement that loop patterns are "even more powerful when combined with" Egison's features) is that the n-queens solver and graph path-finding would fail without backtracking and non-linear patterns, while the combinatorics examples and the tree ancestor traversal might survive. This would produce a feature-dependency map clarifying which capabilities are intrinsic to loop patterns and which are borrowed from the host system, making the construct more portable and its benefits more precisely attributable.
A user study comparing the learnability and error rates of loop patterns against recursive functions for tree and graph traversal tasks. The paper claims conciseness and expressiveness benefits but provides no evidence that programmers other than the author can successfully use loop patterns. A concrete experiment: recruit 20–30 programmers with basic functional programming experience, teach them (a) recursive functions in Egison for tree ancestor enumeration and graph path-finding, and (b) loop patterns for the same tasks (counterbalanced order). Measure: time to correct solution, number of compile/run attempts before correct output, types of errors made, and post-task subjective preference ratings. The hypothesis to test is that loop patterns reduce the time and error rate for structural traversal tasks compared to explicit recursion, but may introduce new error types related to incorrect index range specification or ellipsis placement. A negative result — that programmers find loop patterns harder to use correctly than recursion for these tasks — would be valuable as a caution against adopting the construct without better tooling or pedagogical support.
Integration of loop patterns with an existing graph query language (e.g., a subset of Cypher or Gremlin), measuring coverage and performance on standard graph query benchmarks. The paper claims (Section 5.3, Section 8) that loop patterns combined with simple pattern constructors can express patterns that domain-specific graph query languages handle through built-in functions. A concrete validation: select 20–30 queries from a standard graph query benchmark (e.g., the LDBC Social Network Benchmark, or a subset of the Neo4j movie-graph tutorial queries), implement them using Egison loop patterns on the same graph data, and measure (a) whether the query is expressible at all, (b) lines of code compared to the Cypher/Gremlin version, and (c) runtime on graphs of increasing size (100, 1000, 10000 nodes). The hypothesis from the paper is that loop patterns will express variable-length path queries, ancestor/descendant queries, and cycle-detection queries without built-in path-finding primitives, but may require more verbose pattern specifications and may not match the performance of optimized graph-traversal engines. A negative result — that many standard graph queries require circumvention or fail to express at all with loop patterns — would establish the boundaries of the paper's claim that loop patterns can "represent various patterns by combining the loop patterns and a small number of simple pattern constructors."
Development of a termination checker and static analyzer for loop patterns that warns about infinite expansion, unreachable end numbers, and variable-capture issues before runtime. The paper identifies specific correctness hazards: value-pattern-only termination can cause unbound-variable errors (Section 6.1), end numbers that the index never reaches cause infinite expansion, and ellipsis patterns outside loop contexts have undefined behavior. These are all statically detectable in many cases. A concrete research contribution: design a static analysis that, for a given loop pattern and its surrounding context, determines (a) whether the index variable is guaranteed to reach at least one end number (termination sufficiency), (b) whether all referenced indexed variables ($x_i, $x_(- i 1)) are guaranteed to be bound before use (binding safety), (c) whether every ellipsis appears within the syntactic scope of a loop pattern (scope correctness), and (d) whether end numbers are provably sorted (ordering check). The analysis would not need to be complete — it could flag uncertain cases for runtime checks — but a sound under-approximation that catches the error classes documented in the paper would make loop patterns significantly safer for non-expert use. The paper's formal semantics (Figure 7) provide the operational specification against which the static analysis can be validated.
Exploration of alternative designs that achieve equivalent expressiveness with simpler semantics, as suggested by the paper itself. The paper states (Section 8) that "research for finding simpler language constructs for constructing the loop patterns is also interesting because the semantics... is a bit complicated as a built-in language feature." This is an explicit invitation. The complexity sources are identifiable: the end-number mechanism (Section 6.1) exists because value patterns alone cannot delimit iteration in the presence of non-linear references to future bindings; the loop context stack exists because loops can nest; the three-case ellipsis expansion (Rules 2–4 in Figure 7) exists because intermediate end numbers require branching. A design-exploration paper could systematically vary these decisions: (1) What if the index range is simplified to [start end-pat] with implicit end-number inference, but non-linear references to variables bound after the loop are statically forbidden? (2) What if nesting is restricted to at most one level of loop, eliminating the stack? (3) What if intermediate end numbers are eliminated (only a single termination point, with branching achieved by multiple separate loop patterns)? Each simplification would reduce expressiveness in some dimension; the contribution would be characterizing the expressiveness cost and determining whether the paper's key examples (n-queens, tree ancestors, graph paths, consecutive integers) remain expressible under each simplification.
Practical Applications and Downstream Use Cases
Graph query interfaces that compose a general-purpose pattern language with loop patterns instead of building specialized traversal operators. Graph databases (Neo4j, Amazon Neptune, TigerGraph) and graph-processing frameworks (Apache TinkerPop/Gremlin) currently provide query languages with many built-in traversal commands: variable-length path matching, shortest-path finding, ancestor/descendant enumeration, and cycle detection. Each of these commands requires its own syntax, implementation, optimization, and documentation. The paper demonstrates that several of these queries — ancestor enumeration in trees (Figure 4), shortest path in a directed graph (Figure 5), and Hamiltonian cycle finding (Figure 6, the traveling-salesman pattern) — can be expressed as single declarative patterns using loop patterns combined with simple constructors (edge, node, leaf, cons). If this expressiveness generalizes to the full set of common graph queries, a graph database could replace half a dozen built-in traversal operators with a single general-purpose pattern-matching construct plus a library of pattern definitions. The practical benefit is not conciseness for its own sake, but reduced language surface area — fewer operators to learn, document, maintain, and optimize — and increased composability, since loop patterns can be combined with other pattern constructors (and-patterns, not-patterns, value patterns) to express queries that cross the boundaries of built-in operators (e.g., "find all paths where the edge weights are strictly increasing," which would require post-filtering in Cypher but can be encoded as a value-pattern constraint within the loop pattern's repeat pattern). The paper's contribution here is not a production-ready graph query engine but a proof of concept that such an engine could be built on a smaller, more orthogonal set of primitives.
Embedded pattern-matching DSLs for tree-structured data processing in general-purpose languages. Developers processing XML, JSON, abstract syntax trees, or configuration hierarchies in languages like Python, JavaScript, or Rust currently use a mix of approaches: XPath-like libraries with string-embedded queries, recursive visitor functions with explicit stack management, or ad-hoc traversal code with nested conditionals. None of these provide the combination of declarative structure specification and parameterized repetition that loop patterns offer. A practical library could embed an Egison-inspired pattern matcher with loop patterns as a domain-specific language within a host language, targeting JSON/XML tree processing. The library would allow patterns like "find all JSON objects where a key at depth n has a value equal to the key name at depth n-1" or "validate that an XML document has exactly one title element as a direct child of head" to be written as single declarative patterns rather than as recursive functions with manual bookkeeping. The paper's tree example (Figure 4) demonstrates the core capability: a single pattern that traverses upward from a leaf to enumerate all ancestors, which in XPath would require either the ancestor axis or a recursive function. The practical value is in reducing the cognitive gap between the programmer's structural understanding of the data and the code they must write to query it — the pattern mirrors the structure, while the recursive function obscures it.
Pattern-based test-data generators and property-based testing frameworks. Property-based testing tools (QuickCheck, Hypothesis, fast-check) generate random inputs satisfying structural constraints and check that properties hold. Specifying the structural constraints is itself a pattern-matching problem in reverse: given a pattern describing valid inputs, generate values matching that pattern. Loop patterns, with their explicit index variable and parameterized repetition, could serve as a generator specification language for property-based testing of data structures with count-dependent constraints. For example, a test for a matrix multiplication function could specify "generate an n×m matrix and an m×p matrix, where n, m, and p are randomly chosen" — the loop pattern (loop $i [1 n] <cons (loop $j [1 m] _ ...> ...>) describes the shape constraint declaratively, and the index variables n and m can be randomly instantiated. Because the loop pattern exposes the count as a named variable ($n), the generator can produce instances at different sizes and use the count in subsequent property checks (e.g., "the output matrix should be n×p"). This is more expressive than current property-based testing generators, which typically handle size parameterization through external parameters rather than through the pattern specification itself. The paper does not discuss generation (it focuses on matching), but the declarative structure of loop patterns makes them amenable to reversible interpretation — the same pattern can be read as a specification of what to match or as a specification of what to generate.
When to Prefer This Method
The paper does not position loop patterns against named alternatives in a systematic tradeoff framework. It identifies two limitations of classical repeated patterns (no count dependence, lists only) and argues that loop patterns overcome them, but it does not provide a decision rule for when a programmer should use loop patterns rather than alternative mechanisms (recursive functions, hardcoded patterns, domain-specific query languages). The paper's examples implicitly suggest conditions where loop patterns are advantageous, but these are not articulated as explicit tradeoffs by the paper itself. A forced "Prefer A when X, prefer B when Y" matrix would therefore be fabricated from the reviewer's interpretation rather than drawn from the paper's own argumentation. The paper's contribution is a construct with demonstrated expressiveness, not a comparative evaluation of that construct against alternatives. The decision of when to use loop patterns is left to the programmer's judgment, guided by the examples showing which patterns become expressible that were not expressible before.