Language: EN

programacion-funciones-lambda

What are and how to use lambda functions

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.

Lambda functions are a powerful tool in programming, especially when it comes to writing more concise and readable code.

For example, here we have a myfunc function that simply adds two numbers, and its equivalent in lambda function.

function myfunc(a, b) {
 return a + b
}

(a, b) => a + b

As we can see, the lambda function is a more concise way to define the function, and it does not require a name.

This improves the readability of the code and facilitates the understanding of the program’s logic. Lambda functions are a fundamental tool in functional programming.

Examples of lambda functions in different languages

The general syntax of a lambda function varies depending on the programming language, but it follows a common pattern. Let’s see 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 expenditure 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 higher-order 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 square operation to each element of the numbers list.

Let’s see 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 frequent 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 clausure or enclosure) 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, even if those variables are no longer accessible outside the function in the main code.

In other words, a closure allows a function to retain the state of existing local variables when it was defined, even after the function has finished its execution.

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 within 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 'x' variable from outerFunction
  };
}

In this example, innerFunction is a lambda function defined within 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.

Although myFunction has already finished its execution and the variable x is not accessible from outside myFunction, the closure innerFunction still has access to x.

When we invoke myFunction, this inner 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 automatically capture and create 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 'x' variable by value
    auto innerFunction = [x]() {
        std::cout << x << std::endl; // The lambda uses the 'x' variable from outerFunction
    };

    return innerFunction;
}

int main() {
    auto closureFunc = outerFunction();
    closureFunc(); // Here the inner function (innerFunction) is invoked

    return 0;
}