I would like to propose a new type of pattern for structural pattern
matching.  A motivation will be described later below.

The pattern may be written in a form like

  {<literal or variable>}

(with braces), where <literal or variable> is either a literal pattern
or an identifier (or "NAME" in the structural pattern matching
terminology in the language reference, meaning whatever the name of a
variable can be).  At matching against a value, it should be evaluated
to the series of characters held as the string
format(<literal or variable>) returned (if computed successfully) by
the built-in function ``format``.  If those series of characters
is a valid pattern of another type, then the pattern should be matched
as the obtained pattern.  Otherwise, an exception must be raised.

Here are simple examples to clarify the idea.

```
subject = "x"

pattern = "a"
print(format(pattern)) # --> a

match subject:
    case {pattern}: # interpreted as 'case a', so binds the subject
        # value to the variable "a"
        print(eval(format(pattern))) # --> x

# For comparison,
match subject:
    case pattern: # binds the subject value to the variable "pattern"
        print(pattern) # --> x


# Some more examples.
print(format(a)) # --> x

match subject:
    case {a}: # interpreted as 'case x', so binds the subject value to
        # the variable "x"
        print(eval(format(a))) # --> x
    case {"a"}: # interpreted as 'case a'
        pass
    case "a": # matches a string equal to "a"
        pass
    case {'"a"'}: # interpreted as 'case "a"', so matches a string
        # equal to "a"
        pass
```

What if you format an object other than strings?  Sometimes, a pattern
of this type can be used like a value pattern.

```
from dataclasses import dataclass

@dataclass
class Point:
    x: int
    y: int

point = Point(x=0, y=0)
print(format(point)) # --> Point(x=0, y=0)

match subject:
    case {point}: # interpreted as 'case Point(x=0, y=0)', and matches
        # a Point object at coordinates x=0, y=0
        pass
    case point: # binds the subject value to the variable "point"
        pass
```

Motivation
----------
Consider what control you can have over a match statement using
parameters.  I'm considering the following context.  Suppose you would
like to define a function for which a match statement would be useful
to make it do one of its steps.  The definition of the function you
write may look like

```
def f(*args):
    <some procedure>

    # Do a step with a match statement
    match <expression>:
        case <pattern 1> if <condition 1>:
            <procedure 1>
        case <pattern 2> if <condition 2>:
            <procedure 2>
        case ...
            ...
        ......

    <another procedure>
```

Of the parts of the match statement, <expression>, <condition i> and
<procedure i> will be expressions or series of statements, and can
contain many parameters (variables) whose value may vary with
arguments passed to the function.  Through these parameters, what the
match statement does can be controlled.  I'm talking about such
control.

However, note the parts <pattern i> cannot contain parameters other
than value patterns in them.  This is rather restricted control.

In order to have more control over patterns, one thing you might try
may be to specify with an expression a string whose content will be
the pattern you'd like to use, which can then be considered to be
given parametrized by the value of variables contained in the
expression, and do, e.g.,

```
exec(
f"""match subject:
    case {pattern}:
        pass
"""
)
```

where the variable "pattern" in the braces holds the prametrized
pattern as its value (or you could put the expression for the string
directly between the braces).

However, there is a problem with this approach that this done in the
local scope doesn't do assignments, but only updates locals()
directly, which means, if you want to use e.g., a captured value in
some procedure later, then you would be able to get it not by simply
writing the name of the variable for it but only by doing eval of that
name, or by doing exec of the whole statement (or more) containing the
variable, which would again only update locals().  This will be
inconvenient since you can't necessarily just exec the whole code for
your function
since returning or yielding values can't be done with exec.

Introduction of the proposed type of pattern would solve this problem
since that would enable you to achieve what you want simply with

```
match subject:
    case {pattern}:
        pass
```

Best regards,
Takuo Matsuoka
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/2AFPEYEOCOC6AF6MIGYU5Y72M3XPXYP2/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to