Functional Programming
Functional Programming
updating variables.
Functional programming is about declaring WHAT you want to happen, rather than HOW
you want it to happen.
Imperative/procedural programming declares what should happen, and also exactly HOW
it happens.
ex) Imperative:
num = get_a()
num = transform_a(num)
num = transform_b(num)
return num
functional:
return transform_b(transform_a(get_a()))
Lists are mutable, while tuples are immutable. You can append to a list, but
you cannot append to a tuple. You are able to concatenate tuples together to form a
new tuple.
You may assign this new tuple to an old tuple's variable name, but understand
you aren't changing the old tuple, you're reassigning the variable name.
Scripting is about being imperative, you must write out each step you want the
program to take.
Neither classes nor functions are superior to one another- consider the pros and
cons of each when choosing an approach. However, when conflicted, default to
functions.
Higher order functions are functions that accepts another function as an argument
or returns a function:
Below is an example of a first-class example.
ex) def square(x):
return x * x
# Assign function to variable
f = square
print(f(5))
Below is an example of a Higher-order function:
ex) def square(x):
return x * x
def my_map(func, arg_list):
result = []
for i in arg_list:
result.append(func(i))
return result
Pure functions are functions which always return the same value(s) given the same
arguments (deterministic), and whose evaluation has no side effects.
They do not change the external state of the program (like changing variables
outside of their scope), and they do
ex) def findMax(nums):
max_val = float('-inf')
for num in nums:
if max_val < num:
max_val = num
return max_val
def findMax(nums):
global global_max
for num in nums:
if global_max < num:
global_max = num
Reference vs Value:
Pass by reference: a function can mutate the original value that was passed
into it
pass by value: A function can NOT mutate the orignal value that was passed
into it, it gets a copy
my_num = 1
#my_num = 1
attempt_to_modify(my_num)
#my_num = 1
A recursive function without a base case will loop infinitely, eventually resulting
in a crash.
A base case is an if-statement that causes the loop to end.
ex) def print_chars(word, i):
if i == len(word):
return
print(word[i])
print_chars(word, i + 1)
print_chars("Hello", 0)
The if-statement above causes the function to exit the loop when i equals the
length of the word variable.
Recursion over a tree of dictionaries:
return file_paths
def self_math(math_func):
def inner_func(x):
return math_func(x, x)
return inner_func
square_func = self_math(multiply)
double_func = self_math(add)
print(square_func(5))
# prints 25
print(double_func(5))
# prints 10
the self_math function takes two functions as its argument and returns a new
function
remember to mark variables you want to use outside the function they're defined in
with nonlocal:
ex) def concatter():
doc = ""
def inner_func(word):
# "nonlocal" tells Python to use the doc
# variable from the enclosing scope
nonlocal doc
doc += word + " "
return doc
return inner_func
Currying is a type of function transformationthat takes multiple arguments into a
sequence of functions, each with a single argument.
ex) def sum(a, b):
return a + b
print(sum(1, 2))
# prints 3
Can be curried into:
def sum(a):
def inner_sum(b):
return a + b
return inner_sum
print(sum(1)(2))
# prints 3
You will typically only curry functions when you need to satisfy a specific
function signature, for example, an outside database requires it.
ex) person = {
"is_fat": True,
"is_tall": False
}
the total number of combination the person class can have is four, the
product of 2x2
Sum types however can only be one of several other types. For example, a
single boolean is a sum type
because it can only be either True or False.
Python does not support sum types, but it can mimic them by manually checking
for and handling invalid values.
Enums: a way to represent fixed sets of values; a kind of sum type. Not enforced in
any meaningful way.
def color_to_hex(color):
if color == Color.RED:
return "#FF0000"
if color == Color.GREEN:
return "#00FF00"
if color == Color.BLUE:
return "#0000FF"
raise Exception("Unknown color")