Lambda functions (also known as arrow functions) are a syntax for declaring anonymous functions in a concise and expressive way.
An anonymous function is one that we define without a specific name. That is, unlike regular functions, they are not defined with a complete declaration and do not require an identifier.
The main advantage of lambda functions is their ability to be created and used immediately (this is very useful, for example, if it is a function that we are going to use only once).
For example, here we have a function myfunc
that simply adds two numbers, and its equivalent in a lambda function.
function myfunc(a, b) {
return a + b
}
(a, b) => a + b
As we see, the lambda function is a more concise way of defining the function, and does not require us to give it a name (it is anonymous).
This improves the readability of the code and makes it easier to understand. Lambda functions are a very useful tool in programming, and fundamental in functional programming.
Examples of lambda functions in different languages
The general syntax of a lambda function varies depending on the programming language, but follows a common pattern. Let’s look at an example of the basic structure of a lambda function in different languages:
(parameter_list) => { statements }
[capture_list] (parameter_list) { statements }
(parameter_list) => { statements }
lambda parameter_list: statements
Using lambda functions
Lambda functions are especially useful when simple functionality is required, and defining a complete function would be an unnecessary use of characters.
They can be used in a variety of situations, such as:
Higher-order functions
Lambda functions can be used as arguments in higher-order functions (such as map, filter, and reduce) allowing for more functional and expressive programming.
A function is a higher-order function if it takes a function as an argument or returns a function as a result.
In this case, the lambda function is used as an argument of map
, applying the operation of squaring each element of the list numbers.
Let’s look at an example using Python:
personas_mayores_de_20 = people.Where(person => person.edad > 20);
const personasMayoresDe20 = people.filter(person => person.edad > 20);
personas_mayores_de_20 = filter(lambda person: person.edad > 20, people)
Callbacks and events
Another common use of lambda functions is to be used as callbacks or event handlers. Here is a simple example in JavaScript that shows how to use a lambda function as a click handler on a button:
const button = document.getElementById('myButton');
button.addEventListener('click',
() => { console.log('You clicked the button!');}
);
Closures
A closure (also known as a closure or closing) is a concept that refers to a function along with the lexical environment in which it was created. This means that the function “remembers” the variables that were available at the time of its creation.
In other words, a closure allows a function to maintain the state of existing local variables when it was defined (even after the function has finished executing).
In many programming languages that support lambda functions or arrow functions, such as JavaScript or Python, a closure is automatically created when a lambda function is defined inside another function.
Suppose we are working in JavaScript:
function myFunction() {
let x = 10;
// We define a lambda function (arrow function) inside outerFunction
const innerFunction = () => {
console.log(x); // The lambda function uses the variable 'x' from outerFunction
};
}
In this example, innerFunction
is a lambda function defined inside outerFunction
. The innerFunction
can access the variable x
, even though it exists outside of its scope.
In fact, closures “remember” the value of the variable x
that was available in the scope of outerFunction
at the time it was created.
Even though myFunction
has already finished executing and the variable x
is not accessible from outside of myFunction, the closure innerFunction
still has access to x
.
When we invoke myFunction
, this internal function will execute and display the value of x, which is 10, because it retains the reference to the lexical environment of myFunction
.
function outerFunction() {
let x = 10;
const innerFunction = () => {
console.log(x);
};
return innerFunction;
}
const closureFunc = outerFunction(); // outerFunction has finished and returned innerFunction
closureFunc(); // Here innerFunction is invoked, which still has access to x
Not all languages have automatic captures and closures. For example, in C++ you have to specify the values that are captured.
#include <iostream>
#include <functional>
std::function<void()> outerFunction() {
int x = 10;
// We define a lambda that captures the variable 'x' by value
auto innerFunction = [x]() {
std::cout << x << std::endl; // The lambda uses the variable 'x' from outerFunction
};
return innerFunction;
}
int main() {
auto closureFunc = outerFunction();
closureFunc(); // Here the internal function (innerFunction) is invoked
return 0;
}