110

# Intro to Functional Programming

July 06, 2016

## Transcript

1. ### An intro to Functional Programming Arusha Coders July 6, 2016

by Reuben Cummings @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!?

13. ### def make_rect(length, width): return (length, width) def grow_rect(rect, amount): return

(rect * amount, rect) def get_length (rect): return rect def get_area (rect): return rect * rect
14. ### def make_rect(length, width): return (length, width) def grow_rect(rect, amount): return

(rect * amount, rect) def get_length (rect): return rect def get_area (rect): return rect * rect 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

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 * rect >>> r = make_rect(2, 3) >>> exp_get_area(r) >>> exp_get_area(r) 6 6 expensive!! memoization

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]

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

>>> gen_double(some_ints) <generator object gen_double at 0x...> >>> gen = gen_double(some_ints) >>> next(gen) 2 >>> next(gen) 4

29. ### def gen_double(ints): >>> gen_double(some_ints) <generator object gen_double at 0x...> >>>

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

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

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!!!

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

43. ### >>> from riko.modules import ( ... fetch, truncate, sort, ...

xpathfetchpage as xfetchpage) >>> >>> url = 'news.ycombinator.com/rss' >>> stream = fetch.pipe( ... conf={'url': url}) >>> stream_l = list(stream) >>> len(stream_l) 30 >>> stream_l {'comments': 'http...', 'title': '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 {'title': 'Building a BitTorre...', ...}
45. ### >>> xpath = '/html/body/center/table...' >>> xconf = { ... 'url':

{'subkey': 'comments'}, ... 'xpath': xpath} >>> comments = [ ... xfetchpage.pipe(s, conf=xconf) ... for s in sorted_l] >>> item = next(comments) >>> item.keys() ['p', 'div', 'class', 'content'] >>> item['content'] "Great work! Quite annoying actually..."

47. ### from riko.collections import sync Pipe = sync.SyncPipe sconf = {'rule':

{'sort_key': 'title'}} comments = ( Pipe('fetch', conf={'url': url}) .truncate(conf={'count': '5'}) .sort(conf=sconf) .xpathfetchpage(conf=xconf) .output) item = next(comments)
48. ### head to head functional imperative cacheable ✔ testable ✔ ?

composable ✔ simple ✔ stateful ✔ @reubano #arushacoders