programacion-funciones-lambda

What are and how to use lambda functions

  • 5 min

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 we define without a specific name. That is, unlike regular functions, they are not defined with a full 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’s a function we are going to use only once).

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

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

(a, b) => a + b
Copied!

As we can see, the lambda function is a more concise way to define the function, and it doesn’t require us to give it a name (it’s anonymous).

This improves code readability 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 see an example of the basic structure of a lambda function in different languages:

(parameter_list) => { statements }
Copied!
[capture_list] (parameter_list) { statements }
Copied!
(parameter_list) => { statements }
Copied!
lambda parameter_list: statements
Copied!

Using Lambda Functions

Lambda functions are especially useful when a simple functionality is required, and defining a full function would be an unnecessary waste 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 (like 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.

Let’s see examples in different languages:

personas_mayores_de_20 = people.Where(person => person.edad > 20);
Copied!
const personasMayoresDe20 = people.filter(person => person.edad > 20);
Copied!
personas_mayores_de_20 = filter(lambda person: person.edad > 20, people)
Copied!

Callbacks and Events

Another frequent use of lambda functions is as callbacks or event handlers. Here is a simple example in JavaScript showing how to use a lambda function as a click handler for a button:

const button = document.getElementById('myButton');

button.addEventListener('click', 
                         () => { console.log('You clicked the button!');}
                       );
Copied!

Closures

A closure (also known as a clausura or cierre) is a concept that refers to a function together with the lexical environment in which it was created. This means the function “remembers” the variables that were available at the time of its creation.

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

In many programming languages that support lambda 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
  };
}
Copied!

In this example, innerFunction is a lambda function defined inside outerFunction. The innerFunction can access the variable x, even though it exists outside 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 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
Copied!

Captures and closures are not automatic in all languages. 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;
}
Copied!