"So You Want to be a Functional Programmer" examples, transcribed to Python. Info & additional resources @ https://www.reddit.com/r/learnpython/comments/63su2u/so_you_want_to_be_a_functional_programmer/
##### Higher-Order Functions (1) #####
123 Main St.: Valid Address
Main St.: Invalid Address
Joe Mama: Valid Name
Joe 'l33tz0rs' Mama: Invalid Name
##### Higher-Order Functions (2) #####
10
20
30
40
##### Clojures #####
[['1-1', '1-2'], ['2-1', '2-2'], ['3-1', '3-2']]
[['1-1', '1-2'], ['###', '2-2'], ['$$$', '3-2']]
[['1-1', '1-2'], ['2-1', '2-2'], ['@@@', '3-2']]
[['100', '1-2'], ['200', '2-2'], ['300', '3-2']]
##### Point-Free Notation, Function Composition, Currying #####
140
140
300
300
##### Partial Application #####
{Joe}
{{Joe}}
##### Map #####
[10, 20, 30, 40, 50]
[20, 40, 60, 80, 100]
[1, 2, 3, 4, 5]
##### Filter #####
[1, 3, 5]
[2, 4]
[1, 2, 3, 4, 5]
##### Reduce #####
6
15
[1, 2, 3, 4, 5]
from functools import reduce, partial as F
from syntax_sugar import pipe
import re
def test(name, *results):
result_lines = "\n".join([" " + str(x) for x in results])
print("\n\n\n##### " + name + " #####\n" + result_lines)
def square(x): return(x*x)
def add(x,y): return(x+y)
def multiply(x,y): return(x*y)
def is_even(x): return((x % 2) == 0)
def is_odd(x): return((x % 2) != 0)
########## Higher-Order Functions (1) ##########
# MAKE_REGEX_PARSER returns an object's function
def validate(value, value_type, parse):
if(parse(value)): return(value + ": Valid " + value_type)
else: return(value + ": Invalid " + value_type)
def make_regex_parser(regex_string):
return re.compile(regex_string).match
parse_address = make_regex_parser(r"(?i)^\d+[a-z\. ]+$" )
parse_name = make_regex_parser(r"(?i)^[a-z]+( [a-z]+)?$")
test("Higher-Order Functions (1)",
validate("123 Main St.", "Address", parse_address),
validate("Main St.", "Address", parse_address),
validate("Joe Mama", "Name", parse_name ),
validate("Joe 'l33tz0rs' Mama", "Name", parse_name ),
)
########## Higher-Order Functions (2) ##########
# the MAKE_ADDER functions create & return new functions
def make_adder_lambda(y):
return(lambda x: x + y)
def make_adder_def(y):
def adder(x):
return(x + y)
return(adder)
add_10 = make_adder_lambda(10);
add_20 = make_adder_lambda(20);
add_30 = make_adder_def(30);
add_40 = make_adder_def(40);
test("Higher-Order Functions (2)",
add_10(0),
add_20(0),
add_30(0),
add_40(0),
)
########## Clojures ##########
# FUNCTION_A utilizes nested higher-order functions
# in order to store arguments in parent functions
# where they remain accessible to child functions
def function_A(a1):
a2 = "1-2"
def function_B(b1):
b2 = "2-2"
def function_C(c1):
c2 = "3-2"
return[[a1, a2], [b1, b2], [c1, c2]]
return function_C
return function_B
function_B = function_A("1-1")
function_C = function_B("2-1")
test("Clojures",
function_C("3-1"),
function_B("###")("$$$"),
function_C("@@@"),
function_A("100")("200")("300"),
)
########## Point-Free Notation, Function Composition, Currying ##########
# SQUARE_ADD5_MULTIPLY10_X passes its arguments to [SQUARE, ADD, MULTIPLY]
# with the result of each function being passed to the next
#
# this functionality requires the syntax_sugar module:
# explicit
square_add5_multiply10_1 = pipe() | square | F(add, y=5) | F(multiply, y=10)
# implicit
square_add5_multiply10_2 = pipe() | square | (add, 5) | (multiply, 10)
test("Point-Free Notation, Function Composition, Currying",
square_add5_multiply10_1(3),
square_add5_multiply10_1(3),
square_add5_multiply10_2(5),
square_add5_multiply10_2(5),
)
########## Partial Application ##########
# BRACKET & DOUBLE_BRACKET utilize FUNCTOOLS.PARTIAL
# to create new functions from BRACKET_BASE where
# the PREFIX & SUFFIX arguments are already defined
def bracket_base(x, prefix, suffix):
return(prefix + x + suffix)
bracket = F(bracket_base, prefix="{", suffix="}" )
double_bracket = F(bracket_base, prefix="{{", suffix="}}")
test("Partial Application",
bracket("Joe"),
double_bracket("Joe"),
)
########## Map ##########
# NUMBERS_MULTIPLY10 & NUMBERS_MULTIPLY20 utilize MAP in order to create
# mutated copies of NUMBERS without affecting the original data
numbers = [1, 2, 3, 4, 5]
numbers_multiply10 = map(lambda x: x * 10, numbers)
numbers_multiply20 = map(F(multiply, y=20), numbers)
test("Map",
list(numbers_multiply10),
list(numbers_multiply20),
list(numbers),
)
########## Filter ##########
# ODD_NUMBERS & EVEN_NUMBERS utilize FILTER in order to extract
# specific items from NUMBERS without affecting the original data
numbers = [1, 2, 3, 4, 5]
odd_numbers = filter(is_odd, numbers)
even_numbers = filter(is_even, numbers)
test("Filter",
list(odd_numbers),
list(even_numbers),
numbers,
)
########## Reduce ##########
# NUMBERS_SUM_1 & NUMBERS_SUM_2 utilize FUNCTOOLS.REDUCE
# in order to pass each value in NUMBERS_X to ADD
#
# the first iteration calls ADD(X=NUMBERS_X[0], Y=NUMBERS_X[1]),
# and each subsequent iteration calls ADD(PREVIOUS_RESULT, NUMBERS_X[i])
numbers_1 = [1, 2, 3]
numbers_2 = [1, 2, 3, 4, 5]
numbers_sum_1 = reduce(add, numbers_1)
numbers_sum_2 = reduce(add, numbers_2)
test("Reduce",
numbers_sum_1,
numbers_sum_2,
numbers,
)