FUNCTIONAL
PATTERN
MATCHING
DAKER PINHEIRO
DAKER FERNANDES
PINHEIRO
UFPE
INDT RECIFE
WEBKIT (NIX)
QT, KDE, ...
C++, C, PYTHON, JAVASCRIPT, PROLOG, ...
PYTHON SINCE 2...
PROLOG
botname("Chatty").
chatterbot(['hello'], ['Hello', ',', 'my', 'name', 'is', B]) :-
botname(B).
chatterbot(['how', '...
PATTERN
MATCHING
HASKELL
fib :: Int -> Int
fib 1 = 1;
fib n = n * fib n - 1;
HASKELL
count :: [n] -> n -> n
count (n:tail) n = 1 + count tail n;
count (k:tail) n = count tail n;
count [] _ = 0;
ERLANG
greet(male, Name) ->
io:format("Hello, Mr. ~s!", [Name]);
greet(female, Name) ->
io:format("Hello, Mrs. ~s!", [Name...
PYTHON!!
@patterns
def fib():
if 1: 1
if n: n * fib(n - 1)
DISCLAIMER
PIPINSTALLPATTERNS
... OR CLONE IT.
HOW IT WORKS?
@patterns
if function():
if RULE1: EXPRESSION1
if RULE2: EXPRESSION2
...
if function(*args):
if match(args, ...
PYTHON
@patterns
def fib():
if 1: 1
if n: n * fib(n - 1)
def fib(n):
if n == 1:
return 1
else:
return n * fib(n - 1)
TREE
@patterns
def depth():
if ('Tree', _, left, right): 1 + max(depth(left), depth(right))
if None: 0
def depth(tree):
if...
CHATTERBOT
botname = "Chatty"
@patterns
def answer():
if ['hello']:
"Hello, my name is %s" % botname
if ['hello', 'my', 'n...
CHATTERBOT
botname = "Chatty"
def answer(message):
if message == ['hello']:
return "Hello, my name is %s" % botname
elif m...
BREATH DEEP,
SEEK PEACE
PATTERNS
import sys, inspect, ast, re
from ast import *
def patterns(func):
empty_argspec = inspect.ArgSpec(args=[], varar...
GET_AST
def get_ast(func):
# Get function source
source = inspect.getsource(func)
# Fix extra indent if present
spaces = r...
TRANSFORM_FUNCTION
def transform_function(func_tree):
assert all(isinstance(t, If) for t in func_tree.body), 
'Patterns fu...
TRANSFORM_FUNCTION
...
for test in func_tree.body:
cond = test.test
...
TRANSFORM_FUNCTION
...
if isinstance(cond, (Num, Str, List, Tuple)) and not has_vars(cond):
test.test = make_eq(N('value')...
TRANSFORM_FUNCTION
...
if isinstance(cond, (Num, Str, List, Tuple)) and not has_vars(cond):
test.test = make_eq(N('value')...
TRANSFORM_FUNCTION
...
func_tree.body = map(wrap_tail_expr, func_tree.body)
func_tree.body.append(
Raise(type=N('Mismatch'...
TESTS_AND_ASSIGNS
def destruct_to_tests_and_assigns(topic, pattern):
if isinstance(pattern, (Num, Str)):
return [make_eq(t...
A NEW PEP? :-)
Q & A
DAKER FERNANDES PINHEIRO
HTTP://CODECEREAL.BLOGSPOT.COM
Upcoming SlideShare
Loading in...5
×

Functional Pattern Matching on Python

2,212

Published on

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,212
On Slideshare
0
From Embeds
0
Number of Embeds
49
Actions
Shares
0
Downloads
9
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Functional Pattern Matching on Python

  1. 1. FUNCTIONAL PATTERN MATCHING DAKER PINHEIRO
  2. 2. DAKER FERNANDES PINHEIRO UFPE INDT RECIFE WEBKIT (NIX) QT, KDE, ... C++, C, PYTHON, JAVASCRIPT, PROLOG, ... PYTHON SINCE 2009
  3. 3. PROLOG botname("Chatty"). chatterbot(['hello'], ['Hello', ',', 'my', 'name', 'is', B]) :- botname(B). chatterbot(['how', 'much', 'is' | Expr], ['It', 'is'], Result) :- eval_expression(Expr, Result). chatterbot(['my', 'name', 'is', Name], ['Nice', 'to', 'meet', 'you']) :- assert(name(Name)).
  4. 4. PATTERN MATCHING
  5. 5. HASKELL fib :: Int -> Int fib 1 = 1; fib n = n * fib n - 1;
  6. 6. HASKELL count :: [n] -> n -> n count (n:tail) n = 1 + count tail n; count (k:tail) n = count tail n; count [] _ = 0;
  7. 7. ERLANG greet(male, Name) -> io:format("Hello, Mr. ~s!", [Name]); greet(female, Name) -> io:format("Hello, Mrs. ~s!", [Name]); greet(_, Name) -> io:format("Hello, ~s!", [Name]).
  8. 8. PYTHON!! @patterns def fib(): if 1: 1 if n: n * fib(n - 1)
  9. 9. DISCLAIMER
  10. 10. PIPINSTALLPATTERNS ... OR CLONE IT.
  11. 11. HOW IT WORKS? @patterns if function(): if RULE1: EXPRESSION1 if RULE2: EXPRESSION2 ... if function(*args): if match(args, RULE1): ASSIGNS1 return EXPRESSION1 elif match(args, RULE2): ASSIGNS2 return EXPRESSION2 else: raise Mismatch()
  12. 12. PYTHON @patterns def fib(): if 1: 1 if n: n * fib(n - 1) def fib(n): if n == 1: return 1 else: return n * fib(n - 1)
  13. 13. TREE @patterns def depth(): if ('Tree', _, left, right): 1 + max(depth(left), depth(right)) if None: 0 def depth(tree): if tree: return max(depth(tree[2]), depth(tree[3])) else: return 0
  14. 14. CHATTERBOT botname = "Chatty" @patterns def answer(): if ['hello']: "Hello, my name is %s" % botname if ['hello', 'my', 'name', 'is', name]: "Hello, %s!" % name.capitalize() if ['how', 'much', 'is'] + expr: "It is %d" % eval(' '.join(expr)) if ['bye']: "Good bye!"
  15. 15. CHATTERBOT botname = "Chatty" def answer(message): if message == ['hello']: return "Hello, my name is %s" % botname elif message[:-1] == ['hello', 'my', 'name', 'is']: return "Hello, %s" % message[-1].capitalize() elif message[:3] == ['how', 'much', 'is']: return "It is %d" % eval(' '.join(expr)) elif message == ['bye']: return "Good bye!" else: raise Mismatch()
  16. 16. BREATH DEEP, SEEK PEACE
  17. 17. PATTERNS import sys, inspect, ast, re from ast import * def patterns(func): empty_argspec = inspect.ArgSpec(args=[], varargs=None, keywords=None, defaults=None) assert inspect.getargspec(func) == empty_argspec # TODO: make it not as weird and dirty func.__globals__['Mismatch'] = Mismatch tree = get_ast(func) transform_function(tree.body[0]) return compile_func(func, tree)
  18. 18. GET_AST def get_ast(func): # Get function source source = inspect.getsource(func) # Fix extra indent if present spaces = re_find(r'^s+', source) if spaces: source = re.sub(r'(^|n)' + spaces, 'n', source) return ast.parse(source, func_file(func), 'single')
  19. 19. TRANSFORM_FUNCTION def transform_function(func_tree): assert all(isinstance(t, If) for t in func_tree.body), 'Patterns function should only have if statements' # Adjust arglist and decorators func_tree.args.args.append(Name(ctx=Param(), id='value')) func_tree.decorator_list = [] ...
  20. 20. TRANSFORM_FUNCTION ... for test in func_tree.body: cond = test.test ...
  21. 21. TRANSFORM_FUNCTION ... if isinstance(cond, (Num, Str, List, Tuple)) and not has_vars(cond): test.test = make_eq(N('value'), cond) if isinstance(cond, (Num, Str, Name, Compare, List, Tuple, Dict, BinOp)): tests, assigns = destruct_to_tests_and_assigns(N('value'), cond) test.test = BoolOp(op=And(), values=tests) if tests else V(1) test.body = assigns + test.body else: raise TypeError("Don't know how to match %s" % ...) ...
  22. 22. TRANSFORM_FUNCTION ... if isinstance(cond, (Num, Str, List, Tuple)) and not has_vars(cond): test.test = make_eq(N('value'), cond) if isinstance(cond, (Num, Str, Name, Compare, List, Tuple, Dict, BinOp)): tests, assigns = destruct_to_tests_and_assigns(N('value'), cond) test.test = BoolOp(op=And(), values=tests) if tests else V(1) test.body = assigns + test.body else: raise TypeError("Don't know how to match %s" % ...) ...
  23. 23. TRANSFORM_FUNCTION ... func_tree.body = map(wrap_tail_expr, func_tree.body) func_tree.body.append( Raise(type=N('Mismatch'), inst=None, tback=None))
  24. 24. TESTS_AND_ASSIGNS def destruct_to_tests_and_assigns(topic, pattern): if isinstance(pattern, (Num, Str)): return [make_eq(topic, pattern)], [] elif isinstance(pattern, Name): return [], [make_assign(pattern.id, topic)] elif isinstance(pattern, Compare) and len(pattern.ops) == 1 and isinstance(pattern.ops[0], Is): return [make_call('isinstance', topic, pattern.comparators[0])], [make_assign(pattern.left.id, topic)] ...
  25. 25. A NEW PEP? :-)
  26. 26. Q & A DAKER FERNANDES PINHEIRO HTTP://CODECEREAL.BLOGSPOT.COM
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×