> ## Documentation Index
> Fetch the complete documentation index at: https://genai.codewithsiva.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Functional Programming

> Learn the fundamentals of functional programming in Python using lambda expressions, higher-order functions, and a declarative programming style.

Functional programming is a **programming paradigm** that solves problems by **applying and composing functions**. It combines the power of **higher-order functions** with a **declarative programming style** to write clean, reusable, and expressive code.

Python supports multiple programming paradigms, including:

* Procedural Programming
* Object-Oriented Programming (OOP)
* Functional Programming

Although Python is not a purely functional programming language, it provides several features that make writing functional-style programs simple and effective.

## Learning Objectives

After completing this lesson, you will be able to:

* Explain the functional programming paradigm.
* Understand the role of higher-order functions.
* Create anonymous functions using `lambda`.
* Use built-in higher-order functions such as `map()`, `filter()`, and `reduce()`.
* Write programs using a functional programming style.

## What is Functional Programming?

Functional programming is a style of programming where **functions are the primary building blocks** of a program.

It is based on two key ideas:

* **Higher-order functions**, which allow functions to be passed and returned like any other object.
* **Declarative programming**, where we describe **what** transformation should happen rather than **how** to perform it step by step.

> **Note:** A declarative programming style alone does **not** make a language a functional programming language. For example, SQL is declarative because we specify **what** data we want rather than **how** to retrieve it. Functional programming combines a declarative style with higher-order functions and function composition.

### Procedural Approach

The following program explicitly performs each step.

```python theme={null}
numbers = [1, 2, 3, 4, 5]

result = []

for number in numbers:
    if number % 2 == 0:
        result.append(number * number)

print(result)
```

**Output**

```text theme={null}
[4, 16]
```

### Functional Approach

The same problem can be expressed by composing functions.

```python theme={null}
numbers = [1, 2, 3, 4, 5]

result = map(
    lambda x: x * x,
    filter(lambda x: x % 2 == 0, numbers)
)

print(list(result))
```

**Output**

```text theme={null}
[4, 16]
```

The procedural approach describes **how** to perform each step, whereas the functional approach describes **what transformations** should be applied to the data.

## Characteristics of Functional Programming

* Functions are the primary building blocks.
* Uses higher-order functions extensively.
* Encourages function composition.
* Follows a declarative programming style.
* Focuses on transforming data rather than modifying it.
* Produces modular and reusable code.

## Practice

### Exercise 1

Which two concepts form the foundation of functional programming?

<Accordion title="Solution">
  Functional programming combines:

  * **Higher-order functions**
  * **Declarative programming**
</Accordion>

### Exercise 2

What is the main difference between procedural programming and functional programming?

<Accordion title="Solution">
  * **Procedural programming** focuses on **how** to perform a task step by step.
  * **Functional programming** focuses on **what** transformations should be applied by composing functions.
</Accordion>

### Exercise 3

Is SQL a functional programming language? Why?

<Accordion title="Solution">
  No. SQL follows a **declarative programming style**, but it is **not** a functional programming language because it does not use **higher-order functions** and **function composition** as its primary programming model.
</Accordion>

> Python supports functional programming through features such as **lambda expressions** and built-in higher-order functions like `map()`, `filter()`, and `reduce()`. We'll begin by exploring **lambda functions** in the next section.

## Lambda Functions

A **lambda function** is a small anonymous function created using the `lambda` keyword. It is commonly used when a function is required for a short period of time and does not need a name.

Lambda functions are frequently used with higher-order functions such as `map()`, `filter()`, and `sorted()`.

### Syntax

```python theme={null}
lambda parameters: expression
```

A lambda function:

* Can have one or more parameters.
* Contains only a single expression.
* Automatically returns the result of the expression.
* Does not require the `return` keyword.

### Example

A normal function:

```python theme={null}
def square(x):
    return x * x

print(square(5))
```

The same function using `lambda`:

```python theme={null}
square = lambda x: x * x

print(square(5))
```

**Output**

```text theme={null}
25
```

### Lambda with Multiple Parameters

```python theme={null}
add = lambda a, b: a + b

print(add(10, 20))
```

**Output**

```text theme={null}
30
```

### Lambda with `sorted()`

Lambda functions are commonly used to specify a custom sorting rule.

```python theme={null}
students = [
    ("John", 82),
    ("Alice", 95),
    ("Bob", 76)
]

students.sort(key=lambda student: student[1])

print(students)
```

**Output**

```text theme={null}
[
    ('Bob', 76),
    ('John', 82),
    ('Alice', 95)
]
```

The `key` function returns the second element (marks) of each tuple, so the list is sorted by marks.

### When to Use Lambda Functions

Use lambda functions when:

* The function is simple.
* It is used only once.
* A higher-order function expects another function as an argument.

Avoid lambda functions when:

* The logic is complex.
* Multiple statements are required.
* The function will be reused in multiple places.

## Practice

### Exercise 1

Convert the following function into a lambda function.

```python theme={null}
def cube(x):
    return x ** 3
```

<Accordion title="Solution">
  ```python theme={null}
  cube = lambda x: x ** 3
  ```
</Accordion>

### Exercise 2

Predict the output.

```python theme={null}
multiply = lambda a, b: a * b

print(multiply(5, 6))
```

<Accordion title="Solution">
  ```text theme={null}
  30
  ```

  The lambda function multiplies the two arguments and returns the result.
</Accordion>

### Exercise 3

Predict the output.

```python theme={null}
names = ["John", "Alexander", "Bob"]

names.sort(key=lambda name: len(name))

print(names)
```

<Accordion title="Solution">
  ```text theme={null}
  ['Bob', 'John', 'Alexander']
  ```

  The `key` function returns the length of each string, so the list is sorted in ascending order of string length.
</Accordion>

### Exercise 4

When should you prefer a normal function over a lambda function?

<Accordion title="Solution">
  Use a **normal function** when:

  * The logic is complex.
  * Multiple statements are required.
  * The function will be reused in multiple places.

  Use a **lambda function** when the function is short, simple, and used only once.
</Accordion>

> Lambda functions become especially useful when working with built-in higher-order functions such as **`map()`**, **`filter()`**, and **`reduce()`**, which we'll explore next.

## Built-in Higher-Order Functions

Python provides several **built-in higher-order functions** that simplify common data processing tasks. These functions are widely used in functional programming to transform, filter, and combine data.

The most commonly used built-in higher-order functions are:

* `map()` – Applies a function to every element.
* `filter()` – Selects elements that satisfy a condition.
* `reduce()` – Combines all elements into a single value.
* `sorted()` – Sorts elements using a custom key function.
* `any()` – Returns `True` if at least one element satisfies a condition.
* `all()` – Returns `True` only if all elements satisfy a condition.

We'll explore each of these functions in the following sections.

***

## The `map()` Function

The `map()` function applies a function to **every element** of an iterable and returns a **map object**, which is an iterator.

```python theme={null}
map(function, iterable)
```

Since `map()` returns an iterator, it is commonly converted into a list using the `list()` function.

### Using a Normal Function

```python theme={null}
def square(x):
    return x * x


numbers = [1, 2, 3, 4, 5]

result = map(square, numbers)

print(list(result))
```

**Output**

```text theme={null}
[1, 4, 9, 16, 25]
```

### Using a Lambda Function

```python theme={null}
numbers = [1, 2, 3, 4, 5]

result = map(lambda x: x * x, numbers)

print(list(result))
```

**Output**

```text theme={null}
[1, 4, 9, 16, 25]
```

### Mapping Multiple Iterables

```python theme={null}
numbers1 = [1, 2, 3]
numbers2 = [10, 20, 30]

result = map(lambda x, y: x + y, numbers1, numbers2)

print(list(result))
```

**Output**

```text theme={null}
[11, 22, 33]
```

## Practice

### Exercise 1

Predict the output.

```python theme={null}
numbers = [2, 4, 6]

result = map(lambda x: x + 1, numbers)

print(list(result))
```

<Accordion title="Solution">
  ```text theme={null}
  [3, 5, 7]
  ```

  The lambda function adds `1` to each element, and `map()` applies it to every element in the list.
</Accordion>

### Exercise 2

When should you use `map()`?

<Accordion title="Solution">
  Use `map()` when you want to **apply the same transformation** to every element of an iterable.

  Some common use cases include:

  * Squaring numbers
  * Converting strings to uppercase
  * Calculating percentages
  * Formatting data
</Accordion>

> While `map()` transforms every element, sometimes we need to **select only the elements that satisfy a condition**. For this purpose, Python provides the **`filter()`** function.

## The `filter()` Function

The `filter()` function selects only those elements that satisfy a given condition and returns a **filter object**, which is an iterator.

```python theme={null}
filter(function, iterable)
```

The function passed to `filter()` should return either `True` or `False`.

Since `filter()` returns an iterator, it is commonly converted into a list using the `list()` function.

### Using a Normal Function

```python theme={null}
def is_even(number):
    return number % 2 == 0


numbers = [1, 2, 3, 4, 5, 6]

result = filter(is_even, numbers)

print(list(result))
```

**Output**

```text theme={null}
[2, 4, 6]
```

### Using a Lambda Function

```python theme={null}
numbers = [1, 2, 3, 4, 5, 6]

result = filter(lambda number: number % 2 == 0, numbers)

print(list(result))
```

**Output**

```text theme={null}
[2, 4, 6]
```

### Another Example

Filter students who scored at least 75 marks.

```python theme={null}
students = [
    ("John", 82),
    ("Alice", 95),
    ("Bob", 68),
    ("David", 75)
]

result = filter(lambda student: student[1] >= 75, students)

print(list(result))
```

**Output**

```text theme={null}
[
    ('John', 82),
    ('Alice', 95),
    ('David', 75)
]
```

### Procedural vs Functional

**Procedural Approach**

```python theme={null}
numbers = [1, 2, 3, 4, 5, 6]

result = []

for number in numbers:
    if number % 2 == 0:
        result.append(number)

print(result)
```

**Functional Approach**

```python theme={null}
numbers = [1, 2, 3, 4, 5, 6]

result = filter(lambda number: number % 2 == 0, numbers)

print(list(result))
```

The procedural approach manually checks every element, whereas the functional approach simply specifies the filtering condition.

## Practice

### Exercise 1

Predict the output.

```python theme={null}
numbers = [10, 15, 20, 25]

result = filter(lambda x: x > 15, numbers)

print(list(result))
```

<Accordion title="Solution">
  ```text theme={null}
  [20, 25]
  ```

  The lambda function returns `True` only for values greater than `15`, so `filter()` selects only those elements.
</Accordion>

### Exercise 2

Predict the output.

```python theme={null}
words = ["Python", "AI", "Programming", "ML"]

result = filter(lambda word: len(word) > 2, words)

print(list(result))
```

<Accordion title="Solution">
  ```text theme={null}
  ['Python', 'Programming']
  ```

  The lambda function keeps only the strings whose length is greater than `2`.
</Accordion>

### Exercise 3

When should you use `filter()`?

<Accordion title="Solution">
  Use `filter()` when you want to **select only those elements that satisfy a condition**.

  Some common use cases include:

  * Selecting even or odd numbers
  * Filtering students who passed an exam
  * Removing empty strings
  * Selecting records based on a condition
</Accordion>

***

## The `reduce()` Function

The `reduce()` function repeatedly applies a function to the elements of an iterable and combines them into a **single value**.

Unlike `map()` and `filter()`, `reduce()` is available in the **`functools`** module.

```python theme={null}
from functools import reduce

reduce(function, iterable)
```

### Using a Normal Function

```python theme={null}
from functools import reduce


def add(a, b):
    return a + b


numbers = [1, 2, 3, 4, 5]

result = reduce(add, numbers)

print(result)
```

**Output**

```text theme={null}
15
```

### Using a Lambda Function

```python theme={null}
from functools import reduce

numbers = [1, 2, 3, 4, 5]

result = reduce(lambda a, b: a + b, numbers)

print(result)
```

**Output**

```text theme={null}
15
```

### Another Example

Find the product of all numbers.

```python theme={null}
from functools import reduce

numbers = [2, 3, 4]

result = reduce(lambda a, b: a * b, numbers)

print(result)
```

**Output**

```text theme={null}
24
```

### How `reduce()` Works

```text theme={null}
[1, 2, 3, 4]

Step 1: 1 + 2 = 3
Step 2: 3 + 3 = 6
Step 3: 6 + 4 = 10
```

The final result is returned.

## Practice

### Exercise 1

Predict the output.

```python theme={null}
from functools import reduce

numbers = [2, 4, 6]

result = reduce(lambda a, b: a + b, numbers)

print(result)
```

<Accordion title="Solution">
  ```text theme={null}
  12
  ```

  `reduce()` repeatedly applies the lambda function to combine all elements into a single value.
</Accordion>

### Exercise 2

Predict the output.

```python theme={null}
from functools import reduce

numbers = [1, 2, 3, 4]

result = reduce(lambda a, b: a * b, numbers)

print(result)
```

<Accordion title="Solution">
  ```text theme={null}
  24
  ```

  The multiplication is performed as:

  ```text theme={null}
  1 × 2 = 2
  2 × 3 = 6
  6 × 4 = 24
  ```
</Accordion>

### Exercise 3

When should you use `reduce()`?

<Accordion title="Solution">
  Use `reduce()` when you need to **combine all elements of an iterable into a single value**, such as calculating the:

  * Sum
  * Product
  * Maximum
  * Minimum
</Accordion>

> We have now seen how to **transform** data using `map()`, **filter** data using `filter()`, and **combine** data using `reduce()`. Next, we'll explore other useful built-in higher-order functions such as **`sorted()`**, **`any()`**, and **`all()`**.

## Other Built-in Higher-Order Functions

Besides `map()`, `filter()`, and `reduce()`, Python provides several other higher-order functions that are frequently used in functional programming.

***

## The `sorted()` Function

The `sorted()` function returns a new sorted list. Using the `key` parameter, we can specify a function that determines how the elements should be sorted.

```python theme={null}
sorted(iterable, key=function, reverse=False)
```

### Sorting Numbers

```python theme={null}
numbers = [5, 2, 8, 1, 4]

result = sorted(numbers)

print(result)
```

**Output**

```text theme={null}
[1, 2, 4, 5, 8]
```

### Sorting by Length

```python theme={null}
names = ["John", "Alexander", "Bob"]

result = sorted(names, key=lambda name: len(name))

print(result)
```

**Output**

```text theme={null}
['Bob', 'John', 'Alexander']
```

### Sorting Student Records

```python theme={null}
students = [
    ("John", 82),
    ("Alice", 95),
    ("Bob", 76)
]

result = sorted(
    students,
    key=lambda student: student[1]
)

print(result)
```

**Output**

```text theme={null}
[
    ('Bob', 76),
    ('John', 82),
    ('Alice', 95)
]
```

## Practice

### Exercise 1

Predict the output.

```python theme={null}
numbers = [8, 3, 5, 1]

print(sorted(numbers, reverse=True))
```

<Accordion title="Solution">
  ```text theme={null}
  [8, 5, 3, 1]
  ```

  The `reverse=True` argument sorts the elements in descending order.
</Accordion>

### Exercise 2

When should you use the `key` parameter with the `sorted()` function?

<Accordion title="Solution">
  Use the `key` parameter when the sorting order should be based on a **custom property** of each element rather than the element itself.

  For example:

  * Sort strings by their length.
  * Sort students by their marks.
  * Sort dictionaries by a specific key.
</Accordion>

***

## The `any()` Function

The `any()` function returns **`True`** if **at least one** element in an iterable evaluates to `True`.

```python theme={null}
any(iterable)
```

### Example

```python theme={null}
numbers = [0, 0, 5, 0]

print(any(numbers))
```

**Output**

```text theme={null}
True
```

### Using `any()` with a Generator Expression

```python theme={null}
numbers = [2, 4, 7, 8]

result = any(
    number % 2 != 0
    for number in numbers
)

print(result)
```

**Output**

```text theme={null}
True
```

The expression checks whether **any number is odd**.

## Practice

### Exercise 1

Predict the output.

```python theme={null}
numbers = [0, 0, 0]

print(any(numbers))
```

<Accordion title="Solution">
  ```text theme={null}
  False
  ```

  All elements evaluate to `False`, so `any()` returns `False`.
</Accordion>

***

## The `all()` Function

The `all()` function returns **`True`** only if **every** element in an iterable evaluates to `True`.

```python theme={null}
all(iterable)
```

### Example

```python theme={null}
numbers = [2, 4, 6, 8]

result = all(
    number % 2 == 0
    for number in numbers
)

print(result)
```

**Output**

```text theme={null}
True
```

### Another Example

```python theme={null}
numbers = [2, 4, 5, 8]

result = all(
    number % 2 == 0
    for number in numbers
)

print(result)
```

**Output**

```text theme={null}
False
```

Since one element does not satisfy the condition, `all()` returns `False`.

## Practice

### Exercise 1

Predict the output.

```python theme={null}
values = [True, True, False]

print(all(values))
```

<Accordion title="Solution">
  ```text theme={null}
  False
  ```

  Since one element is `False`, the result is `False`.
</Accordion>

### Exercise 2

What is the difference between `any()` and `all()`?

<Accordion title="Solution">
  * `any()` returns `True` if **at least one** element satisfies the condition.
  * `all()` returns `True` only if **every** element satisfies the condition.
</Accordion>

## Summary of Built-in Higher-Order Functions

| Function   | Purpose                                                       |
| ---------- | ------------------------------------------------------------- |
| `map()`    | Applies a function to every element.                          |
| `filter()` | Selects elements satisfying a condition.                      |
| `reduce()` | Combines all elements into a single value.                    |
| `sorted()` | Sorts elements using a custom key function.                   |
| `any()`    | Returns `True` if at least one element satisfies a condition. |
| `all()`    | Returns `True` only if every element satisfies a condition.   |

> These higher-order functions can be combined to build concise and expressive programs. In the next section, we'll see how to **write programs in a functional programming style** by composing these functions.

## Writing Programs in Functional Style

Functional programming encourages solving problems by **composing small functions**. Instead of writing step-by-step instructions, we describe the sequence of transformations that should be applied to the data.

A common functional programming workflow is:

```text theme={null}
Input Data
    ↓
Filter
    ↓
Transform
    ↓
Combine
    ↓
Result
```

### Example 1: Sum of Squares of Even Numbers

**Procedural Approach**

```python theme={null}
numbers = [1, 2, 3, 4, 5, 6]

result = 0

for number in numbers:
    if number % 2 == 0:
        result += number * number

print(result)
```

**Output**

```text theme={null}
56
```

**Functional Approach**

```python theme={null}
from functools import reduce

numbers = [1, 2, 3, 4, 5, 6]

result = reduce(
    lambda total, value: total + value,
    map(
        lambda number: number * number,
        filter(lambda number: number % 2 == 0, numbers)
    )
)

print(result)
```

**Output**

```text theme={null}
56
```

The data flows through three stages:

```text theme={null}
numbers
   │
   ▼
filter()   → Select even numbers
   │
   ▼
map()      → Square each number
   │
   ▼
reduce()   → Add all squares
   │
   ▼
Result
```

### Example 2: Student Grades

Calculate the average marks of students who scored at least 75 marks.

```python theme={null}
students = [
    ("John", 82),
    ("Alice", 95),
    ("Bob", 68),
    ("David", 75)
]

passed = filter(
    lambda student: student[1] >= 75,
    students
)

marks = map(
    lambda student: student[1],
    passed
)

marks = list(marks)

average = sum(marks) / len(marks)

print(average)
```

**Output**

```text theme={null}
84.0
```

The program first **filters** the required students and then **transforms** the data before calculating the result.

## When to Use Functional Programming

Functional programming works well when:

* Transforming collections of data.
* Filtering data based on conditions.
* Performing calculations on data.
* Building data processing pipelines.
* Writing reusable functions.

Avoid using functional programming when:

* The logic becomes difficult to read.
* Multiple nested function calls reduce clarity.
* A simple loop is easier to understand.

> **Readability is more important than writing everything in a functional style.**

## Real-World Applications

Functional programming concepts are widely used in Python libraries and frameworks, including:

* Data processing and analysis
* Machine learning
* ETL pipelines
* Web APIs
* Asynchronous programming
* Background task processing
* Event-driven systems
* Stream processing

Frameworks such as **FastAPI**, **Pandas**, **PySpark**, **Apache Beam**, and **Dask** make extensive use of higher-order functions and functional programming concepts.

## Key Takeaways

* Functional programming combines **higher-order functions** with a **declarative programming style**.
* Python supports functional programming through **lambda expressions** and built-in higher-order functions.
* `map()` transforms data.
* `filter()` selects data.
* `reduce()` combines data into a single value.
* `sorted()` performs custom sorting using a key function.
* `any()` and `all()` simplify condition checking.
* Functional programming emphasizes composing small functions to build expressive and reusable programs.

## Check Your Understanding

**Question 1**

What are the two main ideas behind functional programming?

<Accordion title="Solution">
  Functional programming combines:

  * **Higher-order functions**
  * **Declarative programming**
</Accordion>

**Question 2**

What is the purpose of a lambda function?

<Accordion title="Solution">
  A lambda function provides a concise way to create a small anonymous function, typically used with higher-order functions.
</Accordion>

**Question 3**

When should you use `map()`?

<Accordion title="Solution">
  Use `map()` when the same transformation needs to be applied to every element of an iterable.
</Accordion>

**Question 4**

When should you use `filter()`?

<Accordion title="Solution">
  Use `filter()` when selecting elements that satisfy a given condition.
</Accordion>

**Question 5**

When should you use `reduce()`?

<Accordion title="Solution">
  Use `reduce()` when combining all elements of an iterable into a single value.
</Accordion>

**Question 6**

What is the difference between `any()` and `all()`?

<Accordion title="Solution">
  * `any()` returns `True` if at least one element satisfies the condition.
  * `all()` returns `True` only if every element satisfies the condition.
</Accordion>

**Question 7**

Why is SQL not considered a functional programming language?

<Accordion title="Solution">
  SQL follows a declarative programming style, but it is not a functional programming language because it does not use higher-order functions and function composition as its primary programming model.
</Accordion>

**Question 8**

What is the main advantage of functional programming?

<Accordion title="Solution">
  Functional programming encourages writing modular, reusable, and expressive programs by composing small functions.
</Accordion>

***

## Practice & Exercises

To reinforce what you've learned in this section (Lambdas, Map, Filter, Reduce, Custom Sorting, any(), and all()), practice with these interactive notebooks:

<CardGroup cols={2}>
  <Card title="Follow-Along Practice" icon="laptop-code">
    Practice writing lambda functions, mapping and filtering collections, reducing lists to single values, using custom sorted keys, and checking conditions with any and all.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/python%20material/python4ai/public/notebooks/basics_exercises/Functional_Programming_Practice.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/python4ai/blob/master/public/notebooks/basics_exercises/Functional_Programming_Practice.ipynb) | <a href="/public/notebooks/basics_exercises/Functional_Programming_Practice.ipynb" download>📥 Download</a>
  </Card>

  <Card title="Practice Exercises" icon="pen-to-square">
    Test your skills with exercises on custom lambda sorting of dictionary products, mapping string lengths, filtering vowel-starting words, reducing list elements to products, and validating group scores.

    [💻 VS Code](vscode://file/Users/sivaprasad/Downloads/python%20material/python4ai/public/notebooks/basics_exercises/Functional_Programming_Exercises.ipynb) | [🚀 Colab](https://colab.research.google.com/github/prasad230776/python4ai/blob/master/public/notebooks/basics_exercises/Functional_Programming_Exercises.ipynb) | <a href="/public/notebooks/basics_exercises/Functional_Programming_Exercises.ipynb" download>📥 Download</a>
  </Card>
</CardGroup>
