[Python-ideas] ML Style Pattern Matching for Python

spir denis.spir at gmail.com
Sat Dec 18 11:23:38 CET 2010


On Sat, 18 Dec 2010 00:21:35 +0100
Eike Welk <eike.welk at gmx.net> 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.
> 
> 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. It is especially useful for writing interpreters, and 
> processing complex trees.

While I generally like pattern matching in FP languages, I think it is not appropriate and not necessary for a general application language like Python. It is an important feature in FP because (1) it matches (!) FP's general point of view or paradigm (2) FP language example application are very much about algorithmics --far less about general designing/modelling.

> 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.  

If ever pattern matching would be considered for inclusion in Python, it would have to fit Python's style, which your proposed syntax really does not. Actually, I find your current-python translation far more readable (except for the enclosing while true hack).
The syntax should look switch/case, probably. A keyword seems necessary to tell apart ordinary switch conditions from pattern matching ones. But it cannot be "match", so let's say "matching". Other changes inline below:

> Proposed Syntax
> ---------------
> 
def foo(x):
>     match x with
      matching x:
>         | 1 ->                      # Equality
          case 1:
>             print("x is equal to 1")
>         | a:int ->                  # Type check
          case int:     # <=> isinstance(x, int) or x.__type__==int ???
>             print("x has type int: %s" % a)
>         | (a, b) ->                 # Tuple unpacking
          case (a, b):
>             print("x is a tuple with length 2: (%s, %s)" % (a, b))
>         | {| a, b |} ->             # Attribute existence and access
          case (.a, .b):
>             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 ->
          case (.a, .b, .c) and 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 ->
          case Foo(.c, .d) and isinstance(c,int) and d == 1:
          case Foo(.c, .d) and c.__type__ == 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))
> 
>         # Default case
>         | _ ->
          else:
>             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.

> [...]

Seems the only annoying aspect in current python is expressing secondary conditions. For instance, if x can be int and have either .a or .b, with different actions in sub-cases. Expressing this "naturally" in python is wrong because if x has neither .a nore .b other cases won't be matched. The only workaround is to have several top-level cases, repeating the top condition about x beeing an int. I guess.
 

> 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

This cannot be! Even less lists. Proposal:
	case []			# check list
	case [n]		# ditto; n must be int telling length
	case {a, b, c}		# check set / elements
	case {a:, b:, c:}	# check dict / keys

An annoying thing is python has no syntax for structured objects. I find acceptable the above used workaround:
	(.a, .b, .c)
to tell about attributes and
	T(.a, .b, .c)
to additionally check the type.

> 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).

Does a:int means isinstance(a,int) or a.__type__==int ?
I would like python to have an 'isa' operator for the latter.

> 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.

I doubt about that for a handful of reasons.

ref to related feature, FWIW: OMeta general structural pattern matching http://tinlizzie.org/ometa/ (with implementation for python)


Denis
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com




More information about the Python-ideas mailing list