Successfully reported this slideshow.
Upcoming SlideShare
×

# Functional Pattern Matching on Python

4,243 views

Published on

Published in: Technology
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

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