2. About me
● Position: Data Engineer at 99
● Production experience: Python, Java, Scala, Go and NodeJS
● Looking at: Erlang and Elixir
● twitter.com/@jesuejunior
● github.com/jesuejunior
3. Agenda
● OOP vs FP (2min)
● About Functional (3min)
● Imperative vs Functional (8min)
● Functions(2min)
● High-Order Functions(10min)
● Lazy Evaluation(8min)
● What did we miss?(4min)
● Next steps?(1min)
5. Object-Oriented Programming (Imperative style)
● Often matches with human style of thinking
● Humans automatically parse the world into objects
● Any well-defined something that has a set of properties
● Just like you mentally divide the world into objects
7. Functional Programming
● Does not (necessarily) divide code into objects
● And can lead to unintuitive code
● In cases where this doesn't match our Intuition
19. Python Hints - operator
In [3]: import operator
#Equivalent to 5 + 3
In [4]: operator.add(5, 3)
Out[4]: 8
#Equivalent to 2 < 5
In [5]: operator.lt(2,5)
Out[5]: True
#Equivalent to [1,2,3][1]
In [6]: operator.itemgetter(1)([1,2,3])
Out[6]: 2
#Equivalent to 3 ** 3
In [7]: operator.pow(2,3)
Out[7]: 8
20. Can we avoid loops?
In [17]: name = None
In [18]: while name is None:
...: name = input()
...: if len(name) < 2:
...: name = None
...:
In [25]: def get_name():
...: name = input()
...: return name if len(name) >= 2 else get_Name()
...:
Recursion
Imperative
21. Tail Recursion
Elixir Python
So sorry...
defmodule Fib do
def fib(0) do 0 end
def fib(1) do 1 end
def fib(n) do
fib(n-1) + fib(n-2)
end
end
IO.puts Fib.fib(10)
26. Function return function as result
def fill(topic):
print("My baloon is " + topic)
def timer(fn):
def inner(*args, **kwargs):
t = time()
fn(*args, **kwargs)
print("took {time}".format(time=time()-t))
return inner
filler = timer(fill)
filler("FP with Python")
27. I've already saw this...
@timer
def fill(topic):
print("My baloon is " + topic)
fill("FP with Python")
28. Partial Function Application
“ The process of fixing a number of
arguments to a function, producing
another function of smaller arity ”
30. Currying
“ The technique of transforming a function
that takes multiple arguments in such a
way that it can be called as a chain of
functions each with a single argument ”
32. Currying
def compose(*funcs):
"""
Return a new function s.t.
compose(f,g,...)(x) == f(g(...(x)))
"""
def inner(data, funcs=funcs):
result = data
for f in reversed(funcs):
result = f(result)
return result
return inner
# >>> times2 = lambda x: x*2
# >>> minus3 = lambda x: x-3
# >>> mod6 = lambda x: x%6
# >>> f = compose(mod6, times2, minus3)
# >>> all(f(i)==((i-3)*2)%6 for i in range(1000000))
# True
33. Currying ( Standard Library)
In [32]: from operator import itemgetter
In [33]: itemgetter(3)([1,2,3,4,5])
Out[33]: 4
In [34]: from operator import attrgetter as attr
In [35]: class Balloon:
...: def __init__(self, name):
...: self.name = "[name] " + name
...:
In [36]: azul = Balloon('Azul')
In [37]: attr('name')(azul)
Out[37]: '[name] Azul'
35. List Comprehension
In [43]: res = [x**2 for x in range(10)]
...: print(res)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
36. List Comprehension (TIME)
python -m cProfile -s cumtime not_lazy_ex.py
3 function calls in 13.734 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 11.936 11.936 13.734 13.734 partial_ex.py:33(<module>)
1 1.798 1.798 1.798 1.798 {range}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
37. List Comprehension (GENEXP)
In [44]: res = (x**2 for x in range(10))
...: print(res)
<generator object <genexpr> at 0x10fd98e60>
In [45]: for i in res: print(i, end=" ")
0 1 4 9 16 25 36 49 64 81
38. List Comprehension (GENEXP)
python -m cProfile -s cumtime lazy_ex.py
3 function calls in 1.812 seconds
Ordered by: cumulative time
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 1.812 1.812 partial_ex.py:30(<module>)
1 1.812 1.812 1.812 1.812 {range}
1 0.000 0.000 0.000 0.000 {method 'disable' of
'_lsprof.Profiler' objects}
42. Python & FP
PRO
● Functions as first-class citizens
● Lambda
● Standard library: map/filter/reduce, itertools, operator,
functools
● Generators can be used for lazy evaluation (in some
cases)
43. Python & FP
CON
● Impossible to separate pure / non pure
● Mutable variables
● Costly mem copy operations
● Imperative style for cycles
● No optimization for tail recursion
45. What did we miss?
ALMOST EVERYTHING
● Errors handling without exceptions
● Pattern matching
● Message passing
● Functional data structures
● Custom data types
● Immutable and mutable
46. What is the next?
● multipledispatch - A relatively sane approach to multiple dispatch in Python.
○ https://github.com/mrocklin/multipledispatch
● pyrsistent - Contains a number of immutable collections.
○ https://github.com/tobgu/pyrsistent
● toolz - Provides a set of utility functions for iterators, functions and dictionaries.
○ https://github.com/pytoolz/toolz
● hypothesis - Is a library for creating unit tests for finding edge cases in your code you wouldn't have thought to look for.
○ https://github.com/HypothesisWorks/hypothesis-python
● more_itertools - Tries to collect useful compositions of iterators that neither itertools nor the recipes included in its docs address.
○ https://github.com/erikrose/more-itertools