Functional Pattern Matching on Python

26
FUNCTIONAL PATTERN MATCHING DAKER PINHEIRO

Transcript of Functional Pattern Matching on Python

Page 1: Functional Pattern Matching on Python

FUNCTIONALPATTERN

MATCHINGDAKER PINHEIRO

Page 2: Functional Pattern Matching on Python

DAKER FERNANDESPINHEIRO

UFPE

INDT RECIFE

WEBKIT (NIX)

QT, KDE, ...

C++, C, PYTHON, JAVASCRIPT, PROLOG, ...

PYTHON SINCE 2009

Page 3: Functional Pattern Matching on Python

PROLOGbotname("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)).

Page 4: Functional Pattern Matching on Python

PATTERNMATCHING

Page 5: Functional Pattern Matching on Python

HASKELLfib :: Int -> Intfib 1 = 1;fib n = n * fib n - 1;

Page 6: Functional Pattern Matching on Python

HASKELLcount :: [n] -> n -> ncount (n:tail) n = 1 + count tail n;count (k:tail) n = count tail n;count [] _ = 0;

Page 7: Functional Pattern Matching on Python

ERLANGgreet(male, Name) -> io:format("Hello, Mr. ~s!", [Name]);greet(female, Name) -> io:format("Hello, Mrs. ~s!", [Name]);greet(_, Name) -> io:format("Hello, ~s!", [Name]).

Page 8: Functional Pattern Matching on Python

PYTHON!!@patternsdef fib(): if 1: 1 if n: n * fib(n - 1)

Page 9: Functional Pattern Matching on Python

DISCLAIMER

Page 10: Functional Pattern Matching on Python

PIP INSTALL PATTERNS... OR CLONE IT.

Page 11: Functional Pattern Matching on Python

HOW IT WORKS?@patternsif 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()

Page 12: Functional Pattern Matching on Python

PYTHON@patternsdef fib(): if 1: 1 if n: n * fib(n - 1)

def fib(n): if n == 1: return 1 else: return n * fib(n - 1)

Page 13: Functional Pattern Matching on Python

TREE@patternsdef 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

Page 14: Functional Pattern Matching on Python

CHATTERBOTbotname = "Chatty"

@patternsdef 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!"

Page 15: Functional Pattern Matching on Python

CHATTERBOTbotname = "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()

Page 16: Functional Pattern Matching on Python

BREATH DEEP,SEEK PEACE

Page 17: Functional Pattern Matching on Python

PATTERNSimport sys, inspect, ast, refrom 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)

Page 18: Functional Pattern Matching on Python

GET_ASTdef 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')

Page 19: Functional Pattern Matching on Python

TRANSFORM_FUNCTIONdef 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 = []

...

Page 20: Functional Pattern Matching on Python

TRANSFORM_FUNCTION... for test in func_tree.body: cond = test.test...

Page 21: Functional Pattern Matching on Python

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

...

Page 22: Functional Pattern Matching on Python

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

...

Page 23: Functional Pattern Matching on Python

TRANSFORM_FUNCTION ... func_tree.body = map(wrap_tail_expr, func_tree.body) func_tree.body.append( Raise(type=N('Mismatch'), inst=None, tback=None))

Page 24: Functional Pattern Matching on Python

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

Page 25: Functional Pattern Matching on Python

A NEW PEP? :-)

Page 26: Functional Pattern Matching on Python

Q & ADAKER FERNANDES PINHEIRO

HTTP://CODECEREAL.BLOGSPOT.COM