
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
participants (1)
-
Matsuoka Takuo