Slide 1

Slide 1 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Oneliner-izer An Exercise in Constrained Coding Chelsea Voss [email protected] May 31, 2016 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 2

Slide 2 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 3

Slide 3 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Write a function f that takes in a string s and returns True only if that string is composed of the characters 'A' and 'a'. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 4

Slide 4 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Write a function f that takes in a string s and returns True only if that string is composed of the characters 'A' and 'a'. def f(s): for char in s: if char != 'a' and char != 'A': return False return True Chelsea Voss PyCon 2016 Oneliner-izer

Slide 5

Slide 5 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Write a function f that takes in a string s and returns True only if that string is composed of the characters 'A' and 'a'. def f(s): for char in s: if char != 'a' and char != 'A': return False return True More fun: solving these in one line. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 6

Slide 6 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Write a function f that takes in a string s and returns True only if that string is composed of the characters 'A' and 'a'. def f(s): for char in s: if char != 'a' and char != 'A': return False return True More fun: solving these in one line. f = lambda s: False not in [char in 'Aa' for char in s] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 7

Slide 7 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee. Write a function f that takes in a string s and returns True only if that string is composed of the characters 'A' and 'a'. def f(s): for char in s: if char != 'a' and char != 'A': return False return True More fun: solving these in one line. f = lambda s: False not in [char in 'Aa' for char in s] f = lambda s: all([char in 'Aa' for char in s]) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 8

Slide 8 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee (2). Estimate π by sampling 100000 random points in the square [0,1] × [0,1] and determining whether they lie in the unit circle centered at (0, 0). Chelsea Voss PyCon 2016 Oneliner-izer

Slide 9

Slide 9 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee (2). Estimate π by sampling 100000 random points in the square [0,1] × [0,1] and determining whether they lie in the unit circle centered at (0, 0). def pi(): ... Chelsea Voss PyCon 2016 Oneliner-izer

Slide 10

Slide 10 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee (2). Estimate π by sampling 100000 random points in the square [0,1] × [0,1] and determining whether they lie in the unit circle centered at (0, 0). def pi(): ... ...or... pi = lambda: sum(1 for t in xrange(100000) if math.sqrt(random.random()**2 + random.random()**2) <= 1) * 4.0 / 100000 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 11

Slide 11 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Writing one-liners Python Bee (2). Estimate π by sampling 100000 random points in the square [0,1] × [0,1] and determining whether they lie in the unit circle centered at (0, 0). def pi(): ... ...or... pi = lambda: sum(1 for t in xrange(100000) if math.sqrt(random.random()**2 + random.random()**2) <= 1) * 4.0 / 100000 ...Can we rewrite any Python code as a one-liner? Chelsea Voss PyCon 2016 Oneliner-izer

Slide 12

Slide 12 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Can we rewrite any Python code as a one-liner? Chelsea Voss PyCon 2016 Oneliner-izer

Slide 13

Slide 13 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Can we rewrite any Python code as a one-liner? Technically, yes. x = MyClass(47) result = x.method() print result [...] → exec "x = MyClass(47)\nresult = x.method()\n[...]" Chelsea Voss PyCon 2016 Oneliner-izer

Slide 14

Slide 14 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Can we rewrite any Python code as a one-liner? Technically, yes. x = MyClass(47) result = x.method() print result [...] → exec "x = MyClass(47)\nresult = x.method()\n[...]" x = MyClass(47); result = x.method(); print result [...] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 15

Slide 15 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Can we rewrite any Python code as a one-liner? Technically, yes. x = MyClass(47) result = x.method() print result [...] → exec "x = MyClass(47)\nresult = x.method()\n[...]" x = MyClass(47); result = x.method(); print result [...] But that’s no fun! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 16

Slide 16 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge More fun: computing with Python expressions. Some tools: Chelsea Voss PyCon 2016 Oneliner-izer

Slide 17

Slide 17 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge More fun: computing with Python expressions. Some tools: List comprehension. >>> lst = [-2, -1, 0, 1, 2, 3, 4] >>> [i * 10 for i in lst if i > 0] [10, 20, 30, 40] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 18

Slide 18 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge More fun: computing with Python expressions. Some tools: List comprehension. >>> lst = [-2, -1, 0, 1, 2, 3, 4] >>> [i * 10 for i in lst if i > 0] [10, 20, 30, 40] Lambda expression. >>> f = lambda x: x * 10 >>> f(10) 4 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 19

Slide 19 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules Chelsea Voss PyCon 2016 Oneliner-izer

Slide 20

Slide 20 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 21

Slide 21 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 22

Slide 22 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 23

Slide 23 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Takeaways: Chelsea Voss PyCon 2016 Oneliner-izer

Slide 24

Slide 24 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Takeaways: This challenge is solvable. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 25

Slide 25 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Takeaways: This challenge is solvable. Lambda calculus! Obscure Python features! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 26

Slide 26 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Takeaways: This challenge is solvable. Lambda calculus! Obscure Python features! Oneliner-izer is a compiler that implements these. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 27

Slide 27 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler The Challenge Rules One line: no newlines. No semicolons, either. No exec or similar. Goal: Implement any Python feature as a Python expression, ideally by abusing lambda and list comprehensions as much as possible. Yes, this is terrible. Takeaways: This challenge is solvable. Lambda calculus! Obscure Python features! Oneliner-izer is a compiler that implements these. Not for use as a software engineering paradigm. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 28

Slide 28 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Overview 1 The Challenge 2 Simple Code Blocks 3 Control Flow 4 Beyond 5 Building the Compiler Chelsea Voss PyCon 2016 Oneliner-izer

Slide 29

Slide 29 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Chelsea Voss PyCon 2016 Oneliner-izer

Slide 30

Slide 30 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 31

Slide 31 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 32

Slide 32 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. print (z + z) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 33

Slide 33 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. print (lambda z: (z + z))(y + y) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 34

Slide 34 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. print (lambda z: (z + z))(y + y) Alternate method. [z + z for z in [y + y]][0] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 35

Slide 35 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. print (lambda y: (lambda z: (z + z))(y + y) )(x + x) Alternate method. [z + z for z in [y + y]][0] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 36

Slide 36 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Simple Code Blocks Convert this into a single line? x = 1 y = x + x z = y + y print z + z Won’t work: (exponential blowup) print (1 + 1) + (1 + 1) + (1 + 1) + (1 + 1) Answer. print (lambda x: (lambda y: (lambda z: (z + z))(y + y) )(x + x))(1) Alternate method. [z + z for z in [y + y]][0] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 37

Slide 37 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about functions? Convert this into a single line? def f(x): return x * 10 print f(3) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 38

Slide 38 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about functions? Convert this into a single line? def f(x): return x * 10 print f(3) Answer. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 39

Slide 39 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about functions? Convert this into a single line? def f(x): return x * 10 print f(3) Answer. print (lambda f: f(3))(lambda x: x * 10) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 40

Slide 40 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about functions? Convert this into a single line? def f(x): return x * 10 print f(3) Answer. print (lambda f: f(3))(lambda x: x * 10) Note that this works as-is with *args and **kwargs! lambda x, y, *args, **kwargs: ... Chelsea Voss PyCon 2016 Oneliner-izer

Slide 41

Slide 41 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about operations that don’t assign to a variable? Suppose do something() has side effects. Convert this into a single line? do_something() print 42 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 42

Slide 42 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about operations that don’t assign to a variable? Suppose do something() has side effects. Convert this into a single line? do_something() print 42 Answer. Since the output value of do_something() isn’t used, we can funnel it to the unused variable _. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 43

Slide 43 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about operations that don’t assign to a variable? Suppose do something() has side effects. Convert this into a single line? do_something() print 42 Answer. Since the output value of do_something() isn’t used, we can funnel it to the unused variable _. print (lambda _: 42)(do_something()) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 44

Slide 44 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about operations that don’t assign to a variable? Suppose do something() has side effects. Convert this into a single line? do_something() print 42 Answer. Since the output value of do_something() isn’t used, we can funnel it to the unused variable _. print (lambda _: 42)(do_something()) Or: print (do_something(), 42)[1] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 45

Slide 45 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about operations that don’t assign to a variable? Suppose do something() has side effects. Convert this into a single line? do_something() print 42 Answer. Since the output value of do_something() isn’t used, we can funnel it to the unused variable _. print (lambda _: 42)(do_something()) Or: print (do_something(), 42)[1] Now we don’t have to have one print: we can define our own print() function and use it just like do something(). Chelsea Voss PyCon 2016 Oneliner-izer

Slide 46

Slide 46 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler A note on print print 1 return 2 Python 3. print is already a function. (lambda _: 2)(print(1)) works just fine. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 47

Slide 47 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler A note on print print 1 return 2 Python 3. print is already a function. (lambda _: 2)(print(1)) works just fine. Python 2. (lambda _: 2)(print 1) is a syntax error. How can we get a __print() function? Chelsea Voss PyCon 2016 Oneliner-izer

Slide 48

Slide 48 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler A note on print print 1 return 2 Python 3. print is already a function. (lambda _: 2)(print(1)) works just fine. Python 2. (lambda _: 2)(print 1) is a syntax error. How can we get a __print() function? Won’t work: In Python 2, we could use from __future__ import print_function. However, that’s not a real import statement, it’s a compiler directive. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 49

Slide 49 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler A note on print print 1 return 2 Python 3. print is already a function. (lambda _: 2)(print(1)) works just fine. Python 2. (lambda _: 2)(print 1) is a syntax error. How can we get a __print() function? Won’t work: In Python 2, we could use from __future__ import print_function. However, that’s not a real import statement, it’s a compiler directive. Instead: __print = __builtins__.__dict__['print'] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 50

Slide 50 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about classes? class Person(object): def __init__(self): ... Chelsea Voss PyCon 2016 Oneliner-izer

Slide 51

Slide 51 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What about classes? class Person(object): def __init__(self): ... → Person = type('Person', (object,), {'__init__': lambda self: ...}) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 52

Slide 52 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 53

Slide 53 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 54

Slide 54 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) (lambda y: None)(f(x)) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 55

Slide 55 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) (lambda _: (lambda y: None)(f(x)) )(__print(x)) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 56

Slide 56 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) (lambda f: (lambda _: (lambda y: None)(f(x)) )(__print(x)) )(lambda x: x * 5) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 57

Slide 57 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) (lambda x: (lambda f: (lambda _: (lambda y: None)(f(x)) )(__print(x)) )(lambda x: x * 5) )(2 + 2) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 58

Slide 58 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Putting it all together x = 2 + 2 def f(x): return x * 5 print x y = f(x) (lambda x: (lambda f: (lambda _: (lambda y: None)(f(x)) )(__print(x)) )(lambda x: x * 5) )(2 + 2) Preserves evaluation order. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 59

Slide 59 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 60

Slide 60 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 61

Slide 61 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. (code_block_1 if boolean else code_block_2) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 62

Slide 62 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. (code_block_1 if boolean else code_block_2) Code blocks: if boolean: x = 5 print x * 100 else: x = 10 print x * 100 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 63

Slide 63 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. (code_block_1 if boolean else code_block_2) Code blocks: if boolean: x = 5 print x * 100 else: x = 10 print x * 100 Problem: code duplication. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 64

Slide 64 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. To de-duplicate, all code after the if/else becomes a continuation: Chelsea Voss PyCon 2016 Oneliner-izer

Slide 65

Slide 65 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. To de-duplicate, all code after the if/else becomes a continuation: def continuation(x): print x * 100 if boolean: x = 5 return continuation(x) else: x = 10 return continuation(x) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 66

Slide 66 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. Final result: Chelsea Voss PyCon 2016 Oneliner-izer

Slide 67

Slide 67 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Convert this into a single line? if boolean: x = 5 else: x = 10 print x * 100 Answer. Conditional expressions ( if else ), plus continuation passing. Final result: (lambda continuation: (lambda x: continuation(x) )(5) if boolean else (lambda x: continuation(x) )(10) )(lambda x: __print(x * 100)) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 68

Slide 68 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler if/else Statements Final result: (lambda continuation: (lambda x: continuation(x) )(5) if boolean else (lambda x: continuation(x) )(10) )(lambda x: __print(x * 100)) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 69

Slide 69 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops Convert this into a single line? x = 5 while x < 20: x = x + 4 print x Chelsea Voss PyCon 2016 Oneliner-izer

Slide 70

Slide 70 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops Convert this into a single line? x = 5 while x < 20: x = x + 4 print x Answer. Conditional expressions and continuation passing... again! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 71

Slide 71 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops Convert this into a single line? x = 5 while x < 20: x = x + 4 print x Answer. Conditional expressions and continuation passing... again! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 72

Slide 72 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → x = 5 def while_loop(x): if x < 20: x = x + 4 while_loop(x) else: print x while_loop(x) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 73

Slide 73 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → x = 5 def while_loop(x): if x < 20: x = x + 4 while_loop(x) else: print x while_loop(x) Problem: while loop is recursive! Not an anonymous function! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 74

Slide 74 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → x = 5 def while_loop(x): if x < 20: x = x + 4 while_loop(x) else: print x while_loop(x) Problem: while loop is recursive! Not an anonymous function! Solution: Y combinator. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 75

Slide 75 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → x = 5 def while_loop(x): if x < 20: x = x + 4 while_loop(x) else: print x while_loop(x) Problem: while loop is recursive! Not an anonymous function! Solution: Y combinator. Y = (lambda f: (lambda x: x(x)) (lambda y: f(lambda: y(y)()))) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 76

Slide 76 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → Problem: while loop is recursive! Not an anonymous function! Solution: Y combinator. Y = (lambda f: (lambda x: x(x)) (lambda y: f(lambda: y(y)()))) (lambda x: (lambda while_loop: while_loop(x)) (Y(lambda while_loop: (lambda x: (lambda x: while_loop(x))(x+4) if x<20 else __print(x)))))(5) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 77

Slide 77 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler while Loops x = 5 while x < 20: x = x + 4 print x → Problem: while loop is recursive! Not an anonymous function! Solution: Y combinator. Y = (lambda f: (lambda x: x(x)) (lambda y: f(lambda: y(y)()))) (lambda x: (lambda while_loop: while_loop(x)) (Y(lambda while_loop: (lambda x: (lambda x: while_loop(x))(x+4) if x<20 else __print(x)))))(5) Worked example here: Wikipedia:Fixed-point_combinator#The_factorial_function Chelsea Voss PyCon 2016 Oneliner-izer

Slide 78

Slide 78 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 79

Slide 79 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Problem: continuation = (lambda x, y, z, kitchen_sink: ...) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 80

Slide 80 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Problem: continuation = (lambda x, y, z, kitchen_sink: ...) New way: [return_value for some_dict['x'] in [42]][0] Chelsea Voss PyCon 2016 Oneliner-izer

Slide 81

Slide 81 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Problem: continuation = (lambda x, y, z, kitchen_sink: ...) New way: [return_value for some_dict['x'] in [42]][0] More concise continuations: continuation = (lambda some_dict: ...) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 82

Slide 82 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Problem: continuation = (lambda x, y, z, kitchen_sink: ...) New way: [return_value for some_dict['x'] in [42]][0] More concise continuations: continuation = (lambda some_dict: ...) Initialize some dict with locals(). Chelsea Voss PyCon 2016 Oneliner-izer

Slide 83

Slide 83 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Storing state Old way: (lambda x: return_value)(42) Problem: continuation = (lambda x, y, z, kitchen_sink: ...) New way: [return_value for some_dict['x'] in [42]][0] More concise continuations: continuation = (lambda some_dict: ...) Initialize some dict with locals(). Bonus: now we can import x from one-lined programs! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 84

Slide 84 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Chelsea Voss PyCon 2016 Oneliner-izer

Slide 85

Slide 85 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Reminder. The items of iterable must be consumed one-by-one in order. We can’t always index into it with iterable[i]. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 86

Slide 86 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Reminder. The items of iterable must be consumed one-by-one in order. We can’t always index into it with iterable[i]. >>> iterable = {10, 20, 30} >>> for item in iterable: ... print item ... 10 20 30 Chelsea Voss PyCon 2016 Oneliner-izer

Slide 87

Slide 87 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Reminder. The items of iterable must be consumed one-by-one in order. We can’t always index into it with iterable[i]. >>> iterable = {10, 20, 30} >>> for item in iterable: ... print item ... 10 20 30 >>> iterable[2] TypeError: 'set' object does not support indexing Chelsea Voss PyCon 2016 Oneliner-izer

Slide 88

Slide 88 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Answer. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 89

Slide 89 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler for Loops Convert this into a single line? total = 0 for item in iterable: total += item print total Answer. Convert to a while loop that consumes the iterable using next. total = 0 items = iter(iterable) sentinel = [] while True: item = next(items, sentinel) if item is sentinel: break total += item print total Chelsea Voss PyCon 2016 Oneliner-izer

Slide 90

Slide 90 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Imports import random as rnd print rnd.choice([1, 2, 3, 10]) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 91

Slide 91 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Imports import random as rnd print rnd.choice([1, 2, 3, 10]) Answer. This is equivalent to: rnd = __import__('random') print rnd.choice([1, 2, 3, 10]) Fortunately, __import__ itself doesn’t need to be imported. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 92

Slide 92 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Raising Errors raise Bad() Chelsea Voss PyCon 2016 Oneliner-izer

Slide 93

Slide 93 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Raising Errors raise Bad() → ([] for [] in []).throw(Bad()) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 94

Slide 94 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Raising Errors raise Bad() → ([] for [] in []).throw(Bad()) assert good carry_on() Chelsea Voss PyCon 2016 Oneliner-izer

Slide 95

Slide 95 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Raising Errors raise Bad() → ([] for [] in []).throw(Bad()) assert good carry_on() → carry_on() if good else ([] for [] in []).throw(AssertionError()) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 96

Slide 96 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except Problem: try: foo() except Bad as ev: bar(ev) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 97

Slide 97 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except Problem: try: foo() except Bad as ev: bar(ev) Solution: abuse the context manager protocol! Chelsea Voss PyCon 2016 Oneliner-izer

Slide 98

Slide 98 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except Solution: abuse the context manager protocol! class Handler: def __enter__(self): pass def __exit__(self, et, ev, tb): if et is not None and issubclass(et, Bad): bar(ev); return True return False with Handler(): foo() Chelsea Voss PyCon 2016 Oneliner-izer

Slide 99

Slide 99 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except class Body: def __enter__(self): pass def __exit__(self, et, ev, tb): foo() class Handler: def __enter__(self): pass def __exit__(self, et, ev, tb): if et is not None and issubclass(et, Bad): bar(ev); return True return False with Handler(), Body(): pass Chelsea Voss PyCon 2016 Oneliner-izer

Slide 100

Slide 100 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except class Body: def __enter__(self): pass def __exit__(self, et, ev, tb): foo() class Handler: def __enter__(self): pass def __exit__(self, et, ev, tb): if et is not None and issubclass(et, Bad): bar(ev); return True return False with contextlib.nested(Handler(), Body()): pass Chelsea Voss PyCon 2016 Oneliner-izer

Slide 101

Slide 101 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except class Body: def __enter__(self): pass def __exit__(self, et, ev, tb): foo() # Why __exit__? Python issue 5251. class Handler: def __enter__(self): pass def __exit__(self, et, ev, tb): if et is not None and issubclass(et, Bad): bar(ev); return True return False with contextlib.nested(Handler(), Body()): pass Chelsea Voss PyCon 2016 Oneliner-izer

Slide 102

Slide 102 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except class Body: def __enter__(self): pass def __exit__(self, et, ev, tb): foo() # Why __exit__? Python issue 5251. class Handler: def __enter__(self): pass def __exit__(self, et, ev, tb): if et is not None and issubclass(et, Bad): bar(ev); return True return False ctx = contextlib.nested(Handler(), Body()) ctx.__enter__() ctx.__exit__(None, None, None) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 103

Slide 103 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except Body = type(’Body’, (), ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: foo() ) Handler = type(’Handler’, (), ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: et is not None and issubclass(et, Bad) and (bar(ev), True)[1] ) ctx = contextlib.nested(Handler(), Body()) ctx.__enter__() ctx.__exit__(None, None, None) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 104

Slide 104 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except (lambda ctx: (ctx.__enter__(), ctx.__exit__(None, None, None)) )(contextlib.nested( type(’Handler’, (), { ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: et is not None and issubclass(et, Bad) and (bar(ev), True)[1] })(), type(’Body’, (), { ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: foo() })())) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 105

Slide 105 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler try/except (lambda ctx: (ctx.__enter__(), ctx.__exit__(None, None, None)) )(contextlib.nested( type(’Handler’, (), { ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: et is not None and issubclass(et, Bad) and (bar(ev), True)[1] })(), type(’Body’, (), { ’__enter__’: lambda self: None, ’__exit__’: lambda self, et, ev, tb: foo() })())) Also implemented: else and finally. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 106

Slide 106 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler What’s Left from module import * yield and generators with Chelsea Voss PyCon 2016 Oneliner-izer

Slide 107

Slide 107 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Building the Compiler ast - for parsing Python files into syntax trees symtable - for elucidating the scope of variables argparse - for parsing command-line arguments unittest - test suite Chelsea Voss PyCon 2016 Oneliner-izer

Slide 108

Slide 108 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Building the Compiler ast - for parsing Python files into syntax trees symtable - for elucidating the scope of variables argparse - for parsing command-line arguments unittest - test suite https://github.com/csvoss/onelinerizer Chelsea Voss PyCon 2016 Oneliner-izer

Slide 109

Slide 109 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Some caveats Constant upper limit to Python parser. $ python onelinerized.py s_push: parser stack overflow MemoryError Chelsea Voss PyCon 2016 Oneliner-izer

Slide 110

Slide 110 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Some caveats Constant upper limit to Python parser. $ python onelinerized.py s_push: parser stack overflow MemoryError $ pypy onelinerized.py Chelsea Voss PyCon 2016 Oneliner-izer

Slide 111

Slide 111 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Some caveats Constant upper limit to Python parser. $ python onelinerized.py s_push: parser stack overflow MemoryError $ pypy onelinerized.py Long loops: Maximum recursion depth exceeded. Chelsea Voss PyCon 2016 Oneliner-izer

Slide 112

Slide 112 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Some caveats Constant upper limit to Python parser. $ python onelinerized.py s_push: parser stack overflow MemoryError $ pypy onelinerized.py Long loops: Maximum recursion depth exceeded. import sys sys.setrecursionlimit(new_limit) Chelsea Voss PyCon 2016 Oneliner-izer

Slide 113

Slide 113 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Oneliner-izing the Oneliner-izer Chelsea Voss PyCon 2016 Oneliner-izer

Slide 114

Slide 114 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Contributors Many thanks to: andersk for contributing many features and some slides asottile and shulinye for contributing code Chelsea Voss PyCon 2016 Oneliner-izer

Slide 115

Slide 115 text

The Challenge Simple Code Blocks Control Flow Beyond Building the Compiler Links Demo: http://onelinepy.herokuapp.com/ Code: https://github.com/csvoss/onelinerizer Further Reading Lambda calculus, Church numerals, combinatory logic To Mock a Mockingbird for logic and combinator puzzles Chelsea Voss PyCon 2016 Oneliner-izer