Skip to content

Commit 4b03b97

Browse files
committed
Commit initial notebook.
0 parents  commit 4b03b97

1 file changed

Lines changed: 312 additions & 0 deletions

File tree

‎Functional Python.ipynb‎

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"metadata": {},
7+
"outputs": [],
8+
"source": [
9+
"!pip install pyeffects"
10+
]
11+
},
12+
{
13+
"cell_type": "markdown",
14+
"metadata": {},
15+
"source": [
16+
"## What is functional programming?\n",
17+
"\n",
18+
"> Functional programming ( FP ) is based on a simple premise with far-reaching implications: we construct our programs using only pure functions—in other words, functions that have no side effects. What are side effects? A function has a side effect if it\n",
19+
"does something other than simply return a result, for example:\n",
20+
"\n",
21+
"- Modifying a variable\n",
22+
"- Modifying a data structure in place\n",
23+
"- Setting a field on an object\n",
24+
"- Throwing an exception or halting with an error\n",
25+
"- Printing to the console or reading user input\n",
26+
"- Reading from or writing to a file\n",
27+
"- Drawing on the screen"
28+
]
29+
},
30+
{
31+
"cell_type": "markdown",
32+
"metadata": {},
33+
"source": [
34+
"## What is referential transparency?\n",
35+
"\n",
36+
"> An expression e is referentially transparent if, for all programs p, all occurrences of e in p can be replaced by the result of evaluating e without affecting the meaning of p. A function f is pure if the expression f(x) is referentially transparent for all referentially transparent x.\n"
37+
]
38+
},
39+
{
40+
"cell_type": "code",
41+
"execution_count": null,
42+
"metadata": {},
43+
"outputs": [],
44+
"source": [
45+
"from typing import List\n",
46+
"\n",
47+
"def add_numbers(numbers: List[int]) -> int:\n",
48+
" sum = 0\n",
49+
" for n in numbers:\n",
50+
" sum = sum + n\n",
51+
" return sum\n",
52+
"\n",
53+
"add_numbers([1, 5, 6, 8])"
54+
]
55+
},
56+
{
57+
"cell_type": "code",
58+
"execution_count": null,
59+
"metadata": {},
60+
"outputs": [],
61+
"source": [
62+
"from typing import List\n",
63+
"\n",
64+
"def add_numbers(numbers: List[int]) -> int:\n",
65+
" # if sum = 0, we should be able to replace sum on the RHS with 0 and get the same result\n",
66+
" sum = 0\n",
67+
" for n in numbers:\n",
68+
" sum = 0 + n\n",
69+
" return sum\n",
70+
"\n",
71+
"add_numbers([1, 5, 6, 8])"
72+
]
73+
},
74+
{
75+
"cell_type": "code",
76+
"execution_count": null,
77+
"metadata": {},
78+
"outputs": [],
79+
"source": [
80+
"# Exercise: Re-write w/o using state"
81+
]
82+
},
83+
{
84+
"cell_type": "markdown",
85+
"metadata": {},
86+
"source": [
87+
"## Dealing with Emptiness: Option"
88+
]
89+
},
90+
{
91+
"cell_type": "code",
92+
"execution_count": null,
93+
"metadata": {},
94+
"outputs": [],
95+
"source": [
96+
"from pyeffects.Option import *\n",
97+
" \n",
98+
"class Name:\n",
99+
" def __init__(self, first_name: str = None, last_name: str = None):\n",
100+
" self.first_name = first_name\n",
101+
" self.last_name = last_name\n",
102+
" \n",
103+
" def get_last_name(self) -> Option:\n",
104+
" return Option.of(self.last_name)\n",
105+
" \n",
106+
" def get_first_name(self) -> Option:\n",
107+
" return Option.of(self.first_name)\n",
108+
" \n",
109+
"\n",
110+
"class Parent:\n",
111+
" def __init__(self, name: Name = None, relationship: str = \"mother\"):\n",
112+
" self.name = name\n",
113+
" self.relationship = relationship\n",
114+
" \n",
115+
" def get_name(self) -> Option:\n",
116+
" return Option.of(self.name)\n",
117+
" \n",
118+
"class Child:\n",
119+
" def __init__(self, name: Name = None, mother: Parent = None, father: Parent = None):\n",
120+
" self.name = name\n",
121+
" self.mother = mother\n",
122+
" self.father = father\n",
123+
" \n",
124+
" def get_name(self) -> Option:\n",
125+
" return Option.of(self.name)\n",
126+
" \n",
127+
" def get_father(self) -> Option:\n",
128+
" return Option.of(self.father)\n",
129+
" \n",
130+
" def get_mother(self) -> Option:\n",
131+
" return Option.of(self.mother)"
132+
]
133+
},
134+
{
135+
"cell_type": "code",
136+
"execution_count": null,
137+
"metadata": {},
138+
"outputs": [],
139+
"source": [
140+
"def get_mothers_first_name(child: Child) -> str:\n",
141+
" if child and child.mother and child.mother.name:\n",
142+
" return child.mother.name.first_name\n",
143+
" else:\n",
144+
" return None\n",
145+
" \n",
146+
"c = Child(\"child 1\", Parent(Name(\"Mom\", \"1\"), \"mother\"), Parent(Name(\"Dad\", \"1\"), \"father\"))\n",
147+
"\n",
148+
"get_mothers_first_name(c)"
149+
]
150+
},
151+
{
152+
"cell_type": "code",
153+
"execution_count": null,
154+
"metadata": {},
155+
"outputs": [],
156+
"source": [
157+
"def get_mothers_first_name2(child: Child) -> str:\n",
158+
" return child.get_mother()\\\n",
159+
" .flat_map(Parent.get_name)\\\n",
160+
" .flat_map(Name.get_first_name)\\\n",
161+
" .get_or_else(\"No name\")\n",
162+
" \n",
163+
"c = Child(\"child 1\", Parent(Name(\"Mom\", \"Mother\"), \"mother\"), Parent(Name(\"Dad\", \"Father\"), \"father\"))\n",
164+
"c1 = Child(\"child 2\")\n",
165+
"# get_mothers_first_name2(c)\n",
166+
"get_mothers_first_name2(c1)"
167+
]
168+
},
169+
{
170+
"cell_type": "markdown",
171+
"metadata": {},
172+
"source": [
173+
"## Dealing with Exceptions: Try"
174+
]
175+
},
176+
{
177+
"cell_type": "code",
178+
"execution_count": null,
179+
"metadata": {},
180+
"outputs": [],
181+
"source": [
182+
"c1_str = \"\"\"\n",
183+
"{\n",
184+
" \"name\": {\n",
185+
" \"first_name\": \"1st\",\n",
186+
" \"last_name\": \"Child\"\n",
187+
" },\n",
188+
" \"mother\": {\n",
189+
" \"name\": {\n",
190+
" \"first_name\": \"Mother\",\n",
191+
" \"last_name\": \"1\"\n",
192+
" }\n",
193+
" }\n",
194+
"}\n",
195+
"\"\"\"\n",
196+
"\n",
197+
"# c2_str = \"\"\"\n",
198+
"# {\n",
199+
"# \"name\": {\n",
200+
"# \"first_name\": \"1st\",\n",
201+
"# \"last_name\": \"Child\"\n",
202+
"# },\n",
203+
"# \"mother\": {\n",
204+
"# \"name\": {\n",
205+
"# \"first_name_wrong\": \"Mother\",\n",
206+
"# \"last_name\": \"1\"\n",
207+
"# }\n",
208+
"# }\n",
209+
"# }\n",
210+
"# \"\"\""
211+
]
212+
},
213+
{
214+
"cell_type": "code",
215+
"execution_count": null,
216+
"metadata": {},
217+
"outputs": [],
218+
"source": [
219+
"import json\n",
220+
"\n",
221+
"def load_name(name_dict: dict) -> Name:\n",
222+
" try:\n",
223+
" n = Name(**name_dict)\n",
224+
" return n\n",
225+
" except TypeError as te:\n",
226+
" raise TypeError(\"Couldn't deserialize Name: \" + str(te))\n",
227+
"\n",
228+
"def load_parent_obj(parent_dict: dict, relationship: str) -> Parent:\n",
229+
" n = None\n",
230+
" if 'name' in parent_dict:\n",
231+
" n = load_name(parent_dict['name'])\n",
232+
" return Parent(name = n, relationship = relationship)\n",
233+
" \n",
234+
"def load_child_obj(json_str: str) -> Child:\n",
235+
" attributes = json.loads(json_str)\n",
236+
" n, m, f = (None, None, None)\n",
237+
" if 'name' in attributes:\n",
238+
" n = load_name(attributes['name'])\n",
239+
" if 'mother' in attributes:\n",
240+
" m = load_parent_obj(attributes['mother'], 'mother')\n",
241+
" if 'father' in attributes:\n",
242+
" f = load_parent_obj(attributes['father'], 'father')\n",
243+
" return Child(n, m, f)\n",
244+
"\n",
245+
"c1 = load_child_obj(c1_str)\n",
246+
"c1.mother.name.first_name\n",
247+
"\n",
248+
"# c2 = load_child_obj(c2_str)"
249+
]
250+
},
251+
{
252+
"cell_type": "code",
253+
"execution_count": null,
254+
"metadata": {},
255+
"outputs": [],
256+
"source": [
257+
"import json\n",
258+
"\n",
259+
"from pyeffects.Try import *\n",
260+
"\n",
261+
"def load_name(name_dict: dict) -> Try:\n",
262+
" return Try.of(lambda: Name(**name_dict['name']))\n",
263+
"\n",
264+
"def load_parent_obj(parent_dict: dict, relationship: str) -> Parent:\n",
265+
" return load_name(parent_dict)\\\n",
266+
" .map(lambda n: Parent(name = n, relationship = relationship))\\\n",
267+
" .get_or_else(Parent(relationship = relationship))\n",
268+
" \n",
269+
"def load_child_obj(json_str: str) -> Child:\n",
270+
" attributes = json.loads(json_str)\n",
271+
" n = load_name(attributes).get_or_else(None)\n",
272+
" m = Try.of(lambda: load_parent_obj(attributes['mother'], 'mother')).get_or_else(None)\n",
273+
" f = Try.of(lambda: load_parent_obj(attriutes['father'], 'father')).get_or_else(None)\n",
274+
" return Child(n, m, f)\n",
275+
"\n",
276+
"c1 = load_child_obj(c1_str)\n",
277+
"c1.mother.name.first_name\n",
278+
"\n",
279+
"c2 = load_child_obj(c2_str)\n",
280+
"print(c2.mother.name)"
281+
]
282+
},
283+
{
284+
"cell_type": "code",
285+
"execution_count": null,
286+
"metadata": {},
287+
"outputs": [],
288+
"source": []
289+
}
290+
],
291+
"metadata": {
292+
"kernelspec": {
293+
"display_name": "Python 3",
294+
"language": "python",
295+
"name": "python3"
296+
},
297+
"language_info": {
298+
"codemirror_mode": {
299+
"name": "ipython",
300+
"version": 3
301+
},
302+
"file_extension": ".py",
303+
"mimetype": "text/x-python",
304+
"name": "python",
305+
"nbconvert_exporter": "python",
306+
"pygments_lexer": "ipython3",
307+
"version": "3.6.11"
308+
}
309+
},
310+
"nbformat": 4,
311+
"nbformat_minor": 4
312+
}

0 commit comments

Comments
 (0)