¿Qué es una lambda (función)?

Resuelto Brian Warshaw asked hace 16 años • 24 respuestas

Para una persona sin experiencia en ciencias de la computación, ¿qué es una lambda en el mundo de la informática?

Brian Warshaw avatar Aug 19 '08 23:08 Brian Warshaw
Aceptado

Lambda proviene de Lambda Calculus y se refiere a funciones anónimas en programación.

¿Por qué es esto genial? Le permite escribir funciones rápidas y desechables sin nombrarlas. También proporciona una buena manera de escribir cierres. Con ese poder puedes hacer cosas como esta.

Pitón

def adder(x):
    return lambda y: x + y
add5 = adder(5)
add5(1)
6

Como puede ver en el fragmento de Python, el sumador de funciones toma un argumento x y devuelve una función anónima, o lambda, que toma otro argumento y. Esa función anónima te permite crear funciones a partir de funciones. Este es un ejemplo simple, pero debería transmitir la potencia que tienen las lambdas y los cierres.

Ejemplos en otros idiomas

perla 5

sub adder {
    my ($x) = @_;
    return sub {
        my ($y) = @_;
        $x + $y
    }
}

my $add5 = adder(5);
print &$add5(1) == 6 ? "ok\n" : "not ok\n";

javascript

var adder = function (x) {
    return function (y) {
        return x + y;
    };
};
add5 = adder(5);
add5(1) == 6

JavaScript (ES6)

const adder = x => y => x + y;
add5 = adder(5);
add5(1) == 6

Esquema

(define adder
    (lambda (x)
        (lambda (y)
           (+ x y))))
(define add5
    (adder 5))
(add5 1)
6

C# 3.5 o superior

Func<int, Func<int, int>> adder = 
    (int x) => (int y) => x + y; // `int` declarations optional
Func<int, int> add5 = adder(5);
var add6 = adder(6); // Using implicit typing
Debug.Assert(add5(1) == 6);
Debug.Assert(add6(-1) == 5);

// Closure example
int yEnclosed = 1;
Func<int, int> addWithClosure = 
    (x) => x + yEnclosed;
Debug.Assert(addWithClosure(2) == 3);

Rápido

func adder(x: Int) -> (Int) -> Int{
   return { y in x + y }
}
let add5 = adder(5)
add5(1)
6

PHP

$a = 1;
$b = 2;

$lambda = fn () => $a + $b;

echo $lambda();

Haskell

(\x y -> x + y) 

Java ver esta publicación

// The following is an example of Predicate : 
// a functional interface that takes an argument 
// and returns a boolean primitive type.

Predicate<Integer> pred = x -> x % 2 == 0; // Tests if the parameter is even.
boolean result = pred.test(4); // true

lua

adder = function(x)
    return function(y)
        return x + y
    end
end
add5 = adder(5)
add5(1) == 6        -- true

Kotlin

val pred = { x: Int -> x % 2 == 0 }
val result = pred(4) // true

Rubí

Ruby es ligeramente diferente en el sentido de que no se puede llamar a una lambda usando exactamente la misma sintaxis que para llamar a una función, pero aún tiene lambdas.

def adder(x)
  lambda { |y| x + y }
end
add5 = adder(5)
add5[1] == 6

Al ser Ruby Ruby, existe una abreviatura de lambdas, por lo que puedes definirla adderde esta manera:

def adder(x)
  -> y { x + y }
end

R

adder <- function(x) {
  function(y) x + y
}
add5 <- adder(5)
add5(1)
#> [1] 6
mk. avatar Aug 19 '2008 16:08 mk.

Una lambda es un tipo de función, definida en línea. Junto con una lambda, también suele tener algún tipo de variable que puede contener una referencia a una función, lambda o no.

Por ejemplo, aquí hay un fragmento de código C# que no utiliza una lambda:

public Int32 Add(Int32 a, Int32 b)
{
    return a + b;
}

public Int32 Sub(Int32 a, Int32 b)
{
    return a - b;
}

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, Add);
    Calculator(10, 23, Sub);
}

Esto llama a Calculadora, transmitiendo no solo dos números, sino también qué método llamar dentro de Calculadora para obtener los resultados del cálculo.

En C# 2.0 obtuvimos métodos anónimos, lo que acorta el código anterior a:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a + b;
    });
    Calculator(10, 23, delegate(Int32 a, Int32 b)
    {
        return a - b;
    });
}

Y luego en C# 3.0 obtuvimos lambdas, lo que hace que el código sea aún más corto:

public delegate Int32 Op(Int32 a, Int32 b);

public void Calculator(Int32 a, Int32 b, Op op)
{
    Console.WriteLine("Calculator: op(" + a + ", " + b + ") = " + op(a, b));
}

public void Test()
{
    Calculator(10, 23, (a, b) => a + b);
    Calculator(10, 23, (a, b) => a - b);
}
Lasse V. Karlsen avatar Aug 19 '2008 16:08 Lasse V. Karlsen

El nombre "lambda" es sólo un artefacto histórico. De lo único que estamos hablando es de una expresión cuyo valor es una función.

Un ejemplo sencillo (usando Scala para la siguiente línea) es:

args.foreach(arg => println(arg))

donde el argumento del foreachmétodo es una expresión para una función anónima. La línea anterior es más o menos lo mismo que escribir algo como esto (no es un código del todo real, pero entenderás la idea):

void printThat(Object that) {
  println(that)
}
...
args.foreach(printThat)

excepto que no necesitas preocuparte por:

  1. Declarar la función en otro lugar (y tener que buscarla cuando vuelvas a visitar el código más adelante).
  2. Nombrar algo que solo estás usando una vez.

Una vez que estás acostumbrado a los valores de función, tener que prescindir de ellos parece tan tonto como tener que nombrar cada expresión, como por ejemplo:

int tempVar = 2 * a + b
...
println(tempVar)

en lugar de simplemente escribir la expresión donde la necesitas:

println(2 * a + b)

La notación exacta varía de un idioma a otro; ¡No siempre se requiere griego! ;-)

joel.neely avatar Aug 29 '2008 18:08 joel.neely