Skip to content

Flat patterns: a blank can take several elements before a literal; no element is lost - #2011

Merged
rocky merged 3 commits into
Mathics3:masterfrom
tombouctou:fix-flat-leading-blanks
Oct 17, 2026
Merged

rocky merged 3 commits into
Mathics3:masterfrom
tombouctou:fix-flat-leading-blanks

Conversation

@tombouctou

Copy link
Copy Markdown
Collaborator

Fixes #1381.

Two bugs in matching a pattern against an expression whose head is Flat.

1. A blank before a literal never takes several elements. basic_match_expression pairs the leading pattern elements whose match count is 1 with the expression's elements one by one, as a fast pre-check. With Flat, a blank x_ can take several elements (x_ in f[x_, z] matches f[x, y] in f[x, y, z]), so the pre-check rejected valid matches. It is already skipped for Orderless heads; this skips it for Flat heads too.

In[1]:= SetAttributes[f, Flat]; f[a_, 0] := zero[a]; f[x, y, 0]
master:  f[x, y, 0]
fixed:   zero[f[x, y]]

2. Elements are dropped. After the first pattern element matched, the next one was matched with first still set. In a partial match (fully=False, as ReplaceAll uses for Flat heads) it could then start anywhere, skipping elements, and the skipped elements were dropped from the result. Only the first element may leave elements before it.

In[2]:= f[x, y, z] /. f[a__, z] :> {a}
master:  {x}
fixed:   {x, y}

In[3]:= f[x, y, z] /. f[a___, y, b___] :> {{a}, {b}}
master:  {{}, {z}}
fixed:   {{x}, {z}}

In[4]:= g[l__, SameTest -> s_] := {{l}, s}  (g Flat, as in #1381)
        g[{1, -1}, {2, 3}, SameTest -> t]
master:  {{{1, -1}}, t}
fixed:   {{{1, -1}, {2, 3}}, t}

Together, the inputs from the Scope section of the Flat reference page now work:

f[a, b, c, d, e] /. f[b, c, d] -> x        f[a, x, e]       (master: unchanged)
f[a, b, c, d, e] /. f[b, c, d] -> f[x, y]  f[a, x, y, e]    (master: unchanged)
f[a, b, c, d, e] /. f[b] -> x              f[a, x, c, d, e] (master: unchanged)
f[a, b, c, d, e] /. f[d, b] -> x           f[a, b, c, d, e] (both; order matters)

Tests: test_flat_patterns in test/builtin/test_patterns.py; 11 of its cases fail on master. Full pytest and doctests pass.

Not changed here (separate differences from WMA): f[a, b, c] /. f[x_] -> {x} gives f[{f[a, b]}, c] rather than {f[a, b, c]}, and MatchQ[f[1, 2], f[_]] gives False.

🤖 Generated with Claude Code

… element is lost

Two bugs in matching against an expression whose head is Flat:

* basic_match_expression pairs leading pattern elements of match count 1
  with expression elements one by one.  With Flat a blank x_ can take
  several elements (x_ in f[x_, z] matches f[x, y] in f[x, y, z]), so
  f[a_, 0] never matched f[x, y, 0].  Skip that shortcut for Flat heads
  as it is already skipped for Orderless ones.

* After the first pattern element matched, the next one was still
  matched with "first" set, so in a partial match (fully=False) it could
  start anywhere, skipping elements; the skipped ones were then dropped
  from the result: f[x, y, z] /. f[a__, z] :> {a} gave {x}.  Only the
  first element may leave elements before it.

This also fixes Mathics3#1381 and the examples in the Scope section of the
Flat reference page (f[a, b, c, d, e] /. f[b, c, d] -> x).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread mathics/core/pattern/base.py Resolved
@rocky

rocky commented Oct 17, 2026

Copy link
Copy Markdown
Member

Wow - this is complicated.

Not changed here (separate differences from WMA): f[a, b, c] /. f[x_] -> {x} gives f[{f[a, b]}, c] rather than {f[a, b, c]}, and MatchQ[f[1, 2], f[_]] gives False.

@tombouctou would you please open an issue so we have this tracked?

LGTM - thanks for fixing this long-standing bug.

@rocky
rocky merged commit 910494e into Mathics3:master Oct 17, 2026
15 checks passed
@tombouctou

Copy link
Copy Markdown
Collaborator Author

Thanks! Opened #2026 for these two (both come from the same thing: with a Flat head, a single blank does not take several elements).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mathics3 signature pattern matching fails when a function has the FLAT attribute

3 participants