Reuben Cummings
July 06, 2016
120

# Intro to Functional Programming

July 06, 2016

## Transcript

1. An intro to Functional
Programming
Arusha Coders July 6, 2016
by Reuben Cummings
@reubano #arushacoders

2. a new way
of thinking
@reubano #arushacoders

3. pure functions

4. pure functions
function
input output
outside
world

5. imperative
version
@reubano #arushacoders

6. class Rectangle(object):
def __init__(self, length, width):
self.length = length
self.width = width
@property
def area(self):
return self.length * self.width
def grow(self, amount):
length = self.length * amount
self.length = length

7. class Rectangle(object):
def __init__(self, length, width):
self.length = length
self.width = width
@property
def area(self):
return self.length * self.width
def grow(self, amount):
length = self.length * amount
self.length = length
internal state

8. class Rectangle(object):
def __init__(self, length, width):
self.length = length
self.width = width
@property
def area(self):
return self.length * self.width
def grow(self, amount):
length = self.length * amount
self.length = length
internal state
state mutation

9. >>> r = Rectangle(2, 3)
>>> r.length
2
>>> r.area
6
>>> r.grow(2)
>>> r.length
4
>>> r.area
12

10. >>> r = Rectangle(2, 3)
>>> r.length
2
>>> r.area
6
>>> r.grow(2)
>>> r.length
4
>>> r.area
12
same commands,
different results!?

11. >>> r = Rectangle(2, 3)
>>> r.length
2
>>> r.area
6
>>> r.grow(2)
>>> r.length
4
>>> r.area
12
same commands,
different results!?

12. functional
version
@reubano #arushacoders

13. def make_rect(length, width):
return (length, width)
def grow_rect(rect, amount):
return (rect[0] * amount, rect[1])
def get_length (rect):
return rect[0]
def get_area (rect):
return rect[0] * rect[1]

14. def make_rect(length, width):
return (length, width)
def grow_rect(rect, amount):
return (rect[0] * amount, rect[1])
def get_length (rect):
return rect[0]
def get_area (rect):
return rect[0] * rect[1]
no state!

15. >>> r = make_rect(2, 3)
>>> get_length(r)
2
>>> grow_rect(r, 2)
(4, 3)
>>> get_area(r)
6
>>> get_length(r)
2
>>> get_area(r)
6
returned a new object

16. >>> r = make_rect(2, 3)
>>> get_length(r)
2
>>> grow_rect(r, 2)
(4, 3)
>>> get_area(r)
6
>>> get_length(r)
2
>>> get_area(r)
6
attributes didn’t change!

17. >>> r = make_rect(2, 3)
>>> get_length(r)
2
>>> grow_rect(r, 2)
(4, 3)
>>> get_area(r)
6
>>> get_length(r)
2
>>> get_area(r)
6
attributes didn’t change!

18. >>> big_r = grow_rect(r, 2)
assign output of the grow
function to a new object

19. >>> big_r = grow_rect(r, 2)
>>> get_area(big_r)
12
>>> get_length(big_r)
4
attributes of new object
are as expected

20. so what??
@reubano #arushacoders

21. from time import sleep
class ExpensiveRectangle(Rectangle):
@property
def area(self):
sleep(5)
return self.length * self.width
>>> r = ExpensiveRectangle(2, 3)
>>> r.area
6
expensive!!
>>> r.area
6

22. from functools import lru_cache
@lru_cache()
def exp_get_area (rect):
sleep(5)
return rect[0] * rect[1]
>>> r = make_rect(2, 3)
>>> exp_get_area(r)
>>> exp_get_area(r)
6
6
expensive!!
memoization

23. lazy evaluation

24. eager
version
@reubano #arushacoders

25. def double(ints):
doubled = []
for i in ints:
doubled.append(i * 2)
return doubled
>>> some_ints = range(1, 11)
>>> double(some_ints)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]

26. lazy
version
@reubano #arushacoders

27. def gen_double(ints):
for i in ints:
yield i * 2
>>> gen_double(some_ints)

>>> gen = gen_double(some_ints)
>>> next(gen)
2
>>> next(gen)
4

28. can we do
better?
@reubano #arushacoders

29. def gen_double(ints):
>>> gen_double(some_ints)

>>> gen = gen_double(some_ints)
>>> next(gen)
2
>>> next(gen)
4
return (i * 2 for i in ints)

30. who
cares??
@reubano #arushacoders

31. def exp_double(ints):
doubled = []
for i in ints:
sleep(5)
doubled.append(i * 2)
return doubled
def exp_gen_double(ints):
for i in ints:
sleep(5)
yield i * 2
expensive!!
expensive!!

32. >>> exp_double(some_ints)
>>> gen = gen_exp_double(some_ints)
>>> next(gen)
>>> next(gen)
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
2
4
>>> next(gen)
6

33. but wait,
there’s
more!
@reubano #arushacoders

34. >>> from itertools import count
>>>
>>> inf_ints = count(1)
>>> double(inf_ints)
inﬁnite iterator!!!

35. >>> from itertools import count
>>>
>>> inf_ints = count(1)
>>> double(inf_ints)
...
>>> gen = gen_double(inf_ints)
>>> next(gen)
42220156
>>> next(gen)
42220158
inﬁnite iterator!!!

36. stream processing

37. >>> stream = range(1, 10)
>>> doubled = [2 * x for x in stream]
>>> doubled
[2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> old = [x for x in doubled if x > 10]
>>> old
[12, 14, 16, 18]
>>> divided = [x / 3 for x in old]
>>> divided
[4.0, 4.6667, 5.3333, 6.0]
transform stream
at each stage

38. >>> stream = range(1, 10)
>>> doubled = [2 * x for x in stream]
>>> doubled
[2, 4, 6, 8, 10, 12, 14, 16, 18]
>>> old = [x for x in doubled if x > 10]
>>> old
[12, 14, 16, 18]
>>> divided = [x / 3 for x in old]
>>> divided
[4.0, 4.6667, 5.3333, 6.0]
user pure functions to
return new streams

39. mini riko
demo
@reubano #arushacoders

40. extracting web data

43. >>> from riko.modules import (
... fetch, truncate, sort,
... xpathfetchpage as xfetchpage)
>>>
>>> stream = fetch.pipe(
... conf={'url': url})
>>> stream_l = list(stream)
>>> len(stream_l)
30
>>> stream_l[0]
'Think...', 'published': 'Tue, 5 Ju...'}
convert generator
into a list

44. >>> truncated = truncate.pipe(
... stream_l, conf={'count': 5})
>>> truncated_l = list(truncated)
>>> len(truncated_l)
5
>>> sorted = sort.pipe(
... truncated_l, conf={
... 'rule': {
... 'sort_key': 'title'}})
>>>
>>> sorted_l = list(sorted)
>>> sorted_l[0]
{'title': 'Building a BitTorre...', ...}

45. >>> xpath = '/html/body/center/table...'
>>> xconf = {
... 'xpath': xpath}
... xfetchpage.pipe(s, conf=xconf)
... for s in sorted_l]
>>> item.keys()
['p', 'div', 'class', 'content']
>>> item['content']
"Great work! Quite annoying actually..."

46. pipeline
version
@reubano #arushacoders

47. from riko.collections import sync
Pipe = sync.SyncPipe
sconf = {'rule': {'sort_key': 'title'}}
Pipe('fetch', conf={'url': url})
.truncate(conf={'count': '5'})
.sort(conf=sconf)
.xpathfetchpage(conf=xconf)
.output)

functional imperative
cacheable ✔
testable ✔ ?
composable ✔
simple ✔
stateful ✔
@reubano #arushacoders

49. Resources
https:/
/docs.python.org/3.5/library/itertools.html
https:/
/docs.python.org/3.5/library/functools.html
https:/
/lodash.com/
http:/
/coffeescript.org/
https:/
https:/
/github.com/nerevu/riko
@reubano #arushacoders

50. Resources
https:/
/github.com/reubano/meza
http:/
/ocw.mit.edu/courses/electrical-engineering-
and-computer-science/6-001-structure-and-
interpretation-of-computer-programs-
spring-2005/
https:/
/www.infoq.com/presentations/Simple-