Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional Pattern Matching on Python

4,243 views

Published on

Published in: Technology
  • 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

×