It's already trivial to make a decorator to do pattern matching, and
if PJE ever finished generic functions, it will get trivial-er. You
just need to create a simple decorator to do something like this:
@basecase
def fac(n):
return n * fac(n -1)
@f.equals(1):
def f(n):
return 1
@f.lessthan(1)
def f(n):
raise Error("n less than 1, operation not defined.")
It's not that pretty, but I don't see any need for a whole new syntax
for what is basically a glorified elif.
On Fri, Dec 17, 2010 at 2:14 PM, Terry Reedy
On 12/17/2010 6:21 PM, Eike Welk wrote:
After learning a bit of Ocaml I started to like its pattern matching features. Since then I want to have a "match" statement in Python. I wonder if anybody else would like this too.
-1 on adding anything like this to core Python. In your example, it is 1. completely redundant with respect to current Python syntax; 2. look like chicken scratches; 3. limited by the chars availables to just a few of the infinity of tests one might want to run. 4. gives special prominence to tuples, which is hardly appropriate to list or iterable-oriented code.
The third point is why Python does not try to everything with syntax symbols. How test that the input is a positive number?How test that the input is a positive number? Type testing is somewhat contrary to duck-typing. For instance, how would you test that the input is an iterable?
ML style pattern matching is syntactic sugar, that combines "if" statements with tuple unpacking, access to object attributes, and assignments. It is a compact, yet very readable syntax for algorithms, that would otherwise require nested "if" statements.
Your example does not use nesting.
It is especially useful for writing interpreters, and
processing complex trees.
Sounds like better suited to a special-purpose 3rd party module, like pyparsing.
Instead of a specification in BNF, here is a function written with the proposed pattern matching syntax. It demonstrates the features that I find most important. The comments and the print statements explain what is done.
Proposed Syntax ---------------
def foo(x): match x with | 1 -> # Equality print("x is equal to 1") | a:int -> # Type check print("x has type int: %s" % a) | (a, b) -> # Tuple unpacking print("x is a tuple with length 2: (%s, %s)" % (a, b)) | {| a, b |} -> # Attribute existence and access print("x is an object with attributes 'a' and 'b'.") print("a=%s, b=%s" % (a, b))
# Additional condition | (a, b, c) with a> b -> print("x is a tuple with length 3: (%s, %s, %s)" % (a, b, c)) print("The first element is greater than the second element.")
# Complex case | {| c:int, d=1 |}:Foo -> print("x has type Foo") print("x is an object with attributes 'c' and 'd'.") print("'c' has type 'int', 'd' is equal to 1.") print("c=%s, d=%s" % (c, d))
# Default case | _ -> print("x can be anything")
Equivalent Current Python -------------------------
The first four cases could be handled more simply, but handling all cases in the same way leads IMHO to more simple code overall.
def foo(x): while True: # Equality if x == 1: print("x is equal to 1") break
# Type check if isinstance(x, int): a = x print("x is an integer: %s" % a) break
# Tuple unpacking if isinstance(x, tuple) and len(x) == 2: a, b = x print("x is a tuple with length 2: (%s, %s)" % (a, b)) break
# Attribute existence testing and access if hasattr(x, "a") and hasattr(x, "b"): a, b = x.a, x.b print("x is an object with attributes 'a' and 'b'.") print("a=%s, b=%s" % (a, b)) break
# Additional condition if isinstance(x, tuple) and len(x) == 3: a, b, c = x if a> b : print("x is a tuple with length 3: (%s, %s, %s)" % (a, b, c)) print("The first element is greater than the second " "element.") break
# Complex case if isinstance(x, Foo) and hasattr(x, "c") and hasattr(x, "d"): c, d = x.c, x.d if isinstance(c, int) and d == 1: print("x has type Foo") print("x is an object with attributes 'c' and 'd'.") print("'c' has type 'int', 'd' is equal to 1.") print("c=%s, d=%s" % (c, d)) break
# Default case print("x can be anything") break
Additional Code to Run Function "foo" -------------------------------------
class Bar(object): def __init__(self, a, b): self.a = a self.b = b
class Foo(object): def __init__(self, c, d): self.c = c self.d = d
foo(1) # Equality foo(2) # Type check foo((1, 2)) # Tuple unpacking foo(Bar(1, 2)) # Attribute existence testing and access foo((2, 1, 3)) # Additional condition foo(Foo(2, 1)) # Complex case foo("hello") # Default case
I left out dict and set, because I'm not sure how they should be handled. I think list should be handled like tuples. Probably there should be a universal matching syntax for all sequences, similarly to the already existing syntax: a, b, *c = s
I don't really like the "->" digraph at the end of each match case. A colon would be much more consistent, but I use colons already for type checking (a:int).
I generally think that Python should acquire more features from functional languages. In analogy to "RPython" it should ultimately lead to "MLPython", a subset of the Python language that can be type checked and reasoned about by external tools, similarly to what is possible with Ocaml.
Eike.
-- Terry Jan Reedy
_______________________________________________ Python-ideas mailing list Python-ideas@python.org http://mail.python.org/mailman/listinfo/python-ideas