Functional Programming in Python: A Practical Basic Guide to Functors, Monads, and Promises.
Tags: python, beginners
Published: 2024-04-18 04:56:35

Functional programming has gained popularity in recent years due to its focus on building programs using pure functions and composition. In Python, a versatile and widely used language, we can also leverage the concepts of functors, monads and promises to write cleaner and more readable code. In this article, we will explore how to use these concepts in Python and provide code examples to illustrate their application.

##Functors

Functionors are structures that allow us to apply functions to wrapped values within a context. In Python, we can take advantage of the built-in capabilities of data types such as lists, dictionaries or sets to accomplish this efficiently.


We want to apply a function that converts all strings in a list to uppercase. We can use the list functor in Python to accomplish this efficiently: 🧑‍💻

> `strings = ["hello", "world", "python"]`

> `upper_strings = list(map(str.upper, strings))`

> `print(upper_strings)  # Output: ['HELLO', 'WORLD', 'PYTHON']`

##Monads

Monads are an extension of functors that allow us to chain operations that return values wrapped in a context. In Python, we can take advantage of libraries such as pymonad to work with monads and simplify the handling of side effects and complex situations.


We want to calculate the area of a triangle, but the base or height values could be None if they are not provided. We can use the Maybe monad to handle these optional values safely: 🧑‍💻

>`from pymonad.maybe import Maybe`

> `def calculate_triangle_area(base, height):
    if base is not None and height is not None:
        return Maybe.just(0.5 * base * height)
    else:
        return Maybe.nothing()`

> `base = 5
height = None`

> `triangle_area = calculate_triangle_area(base, height)`

> `if triangle_area.is_just():
    print("Área del triángulo:", triangle_area.just)
else:
    print("No se pudo calcular el área del triángulo.")
`

##Promises

Promises are another important concept in functional programming that allow us to handle asynchronous operations in a more concise and structured way. In Python, we can use libraries such as asyncio to work with promises and take advantage of asynchronous programming.


Suppose we want to make three HTTP requests asynchronously and process the responses when they are available. We can use the aiohttp library together with asyncio to work with promises and perform asynchronous operations: 🧑‍💻

> `import asyncio
import aiohttp`

> 
`async def fetch_data(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()`

> `async def main():
    urls = ["https://api.example.com/data1", "https://api.example.com/data2", "https://api.example.com/data3"]
    tasks = [fetch_data(url) for url in urls]
    results = await asyncio.gather(*tasks)
    for result in results:
        print("Respuesta:", result)`

> `asyncio.run(main())`


We have explored how to apply the concepts of functors, monads and promises in Python to write cleaner and more readable code. Functors allow us to apply functions to values wrapped in a context, monads allow us to chain operations and handle optional values, and promises help us handle asynchronous operations in a structured way. These concepts are useful for building more robust and flexible programs in Python, taking advantage of the benefits of functional programming. 😉