<jupyter_start><jupyter_text>This notebook is specifically made for Python3.x versions   Functional Composition<jupyter_code># Takes two functions and chains them like h(g(x))
def compose_functions(h_x, g_x):
    def final_func(*args, **kwargs):
        return h_x(g_x(*args, **kwargs))
    return final_func
import re 

def add_suffix(my_string):
    return my_string + ' the suffix, was finally added!!!'

def remove_punctuation(my_string):
    return re.sub(r'[^\w\s]','',my_string)

composed_f = compose_functions(remove_punctuation, add_suffix)
composed_f("Hello! World?")
#remove_punctuation("Hello! World? the suffix, was finally added!!!")
composed_f2 = compose_functions(add_suffix, remove_punctuation)
composed_f2("Hello! World?")
#add_suffix("Hello World")<jupyter_output><empty_output><jupyter_text>Currying  Using Partial from functools<jupyter_code>def do_some_ops(a, b, c, d):
    return a * b + c - d
from functools import partial

# bind b
dso_f_b = partial(do_some_ops, b=10)

# bind c
dso_f_c = partial(dso_f_b, c=100)

# bind d
dso_f_d = partial(dso_f_c, d=1)


# call the function for some value of a
dso_f_d(9) #do_some_ops(9)(10)(100)(1)
# The above call is same as 
do_some_ops(9, 10, 100, 1)
def predict_land_prices(yr_sold, yr_bought, initial_price, area):
    return initial_price + area*(yr_sold-yr_bought)*20 + 2000
# Year bought, area and initial price are fixed for any land

# bind year bought
plp_yr_bought = partial(predict_land_prices, yr_bought=2012)

# bind initial price
plp_initial_price = partial(plp_yr_bought, initial_price=50000)

#bind plot area
plp_area = partial(plp_initial_price, area=1000)


plp_area(2022)
# The above call is same as
predict_land_prices(2022, 2012, 50000, 1000)
plp_area(2023)
plp_area(2030)<jupyter_output><empty_output><jupyter_text>Using Decorators<jupyter_code>from inspect import signature

# Create a decorator
def curry_func(my_func):
    
    # define inner function
    def inner_wrap(args):
        
        # Check no. of paramters in function signature
        if len(signature(my_func).parameters) == 1:
            return my_func(args)
        
        # If more than 1 paramter recursively apply
        # the decorator and call partial
        else:
            return curry_func(partial(my_func, args))
        
    return inner_wrap
@curry_func
def do_some_ops(a, b, c, d):
    return a * b + c - d
do_some_ops(9)(10)(100)(1)
@curry_func
def predict_land_prices(yr_sold, yr_bought, initial_price, area):
    return initial_price + area*(yr_sold-yr_bought)*20 + 2000
predict_land_prices(2022)(2012)(50000)(1000)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10361904761904762, 'fraction_numerical': 0.039619047619047616, 'mean_word_length': 4.901123595505618, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '489911', 'license': 'Apache-2.0', 'n_tokens_mistral': 1038, 'n_tokens_neox': 950, 'n_words': 233, 'path': '_src/Section 7/7.1 Currying in Python 3.ipynb', 'repo_name': 'paullewallencom/functional-programming-978-1-7889-9029-5', 'size': '2625'}