 # Higher-Order Functions Note: this page has been created with the use of AI. Please take caution, and note that the content of this page does not necessarily reflect the opinion of Cratecode.

Higher-order functions are like the wizards of the programming world - they have the power to wield other functions as their weapons. In functional programming, they play a crucial role in keeping our code clean, modular, and reusable. So, let's don our wizard robes and dive into the magical world of higher-order functions.

## What are Higher-Order Functions?

A higher-order function is a function that either:

1. Takes one or more functions as arguments.
2. Returns a function as its result.

In simpler terms, higher-order functions are functions that can work with other functions. They allow us to create more abstract and reusable code by treating functions as data, which can be passed around and manipulated.

Here's a basic example using lambda functions in Python:

``````def apply(func, x, y):
return func(x, y)

add = lambda x, y: x + y
multiply = lambda x, y: x * y

result1 = apply(add, 5, 3)        # result1 = 8
result2 = apply(multiply, 5, 3)    # result2 = 15``````

In this example, the `apply` function takes a function (`func`) and two arguments (`x`, `y`). It then calls the `func` with `x` and `y`. We pass `add` and `multiply` functions as arguments to `apply` and get the respective results.

## Common Higher-Order Functions

Functional programming languages usually come with a set of built-in higher-order functions that you'll likely encounter. Some common ones are `map`, `filter`, and `reduce`.

### Map

`map` applies a given function to each item of an iterable (like a list) and returns a new iterable with the results. Here's an example in JavaScript:

``````const numbers = [1, 2, 3, 4];
const square = x => x * x;
const squaredNumbers = numbers.map(square); // [1, 4, 9, 16]``````

### Filter

`filter` creates a new iterable with only the elements that pass a certain condition (test function). Here's an example in Python:

``````numbers = [1, 2, 3, 4, 5, 6]
is_even = lambda x: x % 2 == 0
even_numbers = list(filter(is_even, numbers)) # [2, 4, 6]``````

### Reduce

`reduce` takes an iterable and a function, then successively applies the function to the elements, accumulating the result. Here's an example in JavaScript:

``````const numbers = [1, 2, 3, 4];
const add = (x, y) => x + y;
const sum = numbers.reduce(add, 0); // 10``````

## Closures and Currying

Higher-order functions can also return functions, which brings us to closures and currying. A closure is a function that "closes over" some variables from its surrounding scope, allowing it to remember the values even after the outer function has completed.

Currying is a technique where a function that takes multiple arguments is decomposed into a series of functions that each take a single argument. This can make the code more readable and modular. Here's an example in Python:

``````def greet(greeting):
def greet_person(name):
return f"{greeting}, {name}!"
return greet_person

hello = greet("Hello")
print(hello("Alice"))  # "Hello, Alice!"``````

In this example, `greet` is a higher-order function that returns the `greet_person` closure. The `greet_person` closure "remembers" the `greeting` value from its outer scope.

Now that we've explored the mystical world of higher-order functions, you're ready to wield their power in your functional programming adventures. Remember, with great power comes great responsibility - use higher-order functions responsibly for cleaner, more modular, and reusable code. Happy coding!