Expresión lambda
En el ámbito de la programación, una expresión lambda, también denominada función lambda, función literal o función anónima, es una subrutina definida que no está enlazada a un identificador. Las expresiones lambda a menudo son argumentos que se pasan a funciones de orden superior, o se usan para construir el resultado de una función de orden superior que necesita devolver una función.[1] Si la función solo se usa una vez o un número limitado de veces, una expresión lambda puede ser sintácticamente más simple que usar una función con nombre. Las funciones lambda son muy comunes en los lenguajes de programación funcional y en otros lenguajes con funciones de primera clase, en los que cumplen el mismo papel para el tipo de función que los literales para otros tipos de datos.
Las funciones lambda se originaron debido al trabajo de Alonzo Church en su cálculo lambda ─en el que todas las funciones eran anónimas─ en 1936, antes de la invención de las computadoras electrónicas.[2]
En varios lenguajes de programación, las funciones anónimas son introducidas bajo el nombre lambda y generalmente también son referidas como lambdas y abstracciones lambda. Las funciones anónimas han sido un aspecto integrado de los lenguajes de programación desde el origen del lenguaje Lisp en 1958, y un número creciente de lenguajes de programación admite funciones anónimas.
Las funciones anónimas son una forma de funciones anidadas al permitir el acceso a variables ─no locales─ dentro de la función contenedora. Esto significa que las funciones anónimas necesitan ser implementadas utilizando clausuras o closures.
A diferencia de las funciones nombradas anidadas, las funciones anónimas no pueden ser recursivas sin la asistencia de un operador de punto fijo o enlazarlas a un nombre.[3]
Usos y Funciones
Las expresiones lambda pueden ser utilizadas para contener funcionalidades que no necesitan ser nombradas y normalmente se utilizan en un tiempo corto. Algunos ejemplos notables incluyen las clausuras y la currificación.
El uso de expresiones lambda es un tema de estilo. Usar expresiones lambda como la única forma de resolver un problema es erróneo; cada expresión lambda puede en su lugar ser reemplazada por una función nombrada y llamada por su nombre. Algunos programadores utilizan las expresiones lambda para encapsular código específico y no reutilizable para así evitar código basura con muchas pequeñas funciones de pocas líneas.
En algunos lenguajes de programación, las expresiones lambda normalmente son implementadas con propósitos específicos como la vinculación de eventos a devoluciones de llamada, o instanciar la función para valores particulares, lo que puede ser más eficiente, más legible, y menos propenso a errores que llamar a una función de nombre más genérico. El código en las siguientes secciones está escrito en Python 2.x.
Clasificación
Al intentar ordenar de una manera no estándar, puede ser más fácil contener la lógica de comparación como una expresión lambda en lugar de crear una función con nombre. La mayoría de los lenguajes de programación proporcionan una función de clasificación genérica que implementa un algoritmo de ordenación que puede ordenar objetos arbitrarios.
Esta función normalmente acepta una función de comparación arbitraria a la cual se le suministra dos elementos, la función indica si estos son iguales o si uno es mayor o menor que el otro (usualmente se indica mediante la devolución de un número negativo, cero o un número positivo). Considere clasificar una lista de cadenas por la longitud de la cadena:
>>> a = ['casa', 'automóvil', 'avión'] >>> a.sort(lambda x,y: cmp(len(x), len(y))) >>> print(a) ['casa', 'avión', 'automóvil']
La función anónima en este ejemplo es la expresión lambda:
lambda x,y: cmp(...)
La función anónima acepta dos argumentos, x
e y
, y devuelve la comparación entre ellos utilizando la función incorporada cmp()
. Otro ejemplo sería la clasificación de elementos en una lista por el nombre de su clase (en Python, todo tiene una clase):
>>> a = [10, 'number', 11.2] >>> a.sort(lambda x,y: cmp(x.__class__.__name__, y.__class__.__name__)) >>> print(a) [11.2, 10, 'number']
Nótese que 11.2
tiene nombre de clase "float
", 10
tiene nombre de clase "int
", y "'number'
" tiene nombre de clase "str
". El orden ordenado es "float
", "int
", luego "str
".
Clausuras
Las clausuras son funciones evaluadas en un entorno que contienen variables ligadas. El siguiente ejemplo vincula la variable "threshold" (umbral) en una función anónima que compara la entrada con el umbral.
def comp(threshold): return lambda x: x < threshold
Esto se puede utilizar como una especie de generador de funciones de comparación:
>>> func_a = comp(10) >>> func_b = comp(20) >>> print func_a(5), func_a(8), func_a(13), func_a(21) True True False False >>> print func_b(5), func_b(8), func_b(13), func_b(21) True True True False
Sería poco práctico crear una función para cada función de comparación posible y puede ser demasiado inconveniente para mantener el umbral alrededor para su uso posterior. Independientemente de la razón por la que se utiliza una clausura, la función anónima es la entidad que contiene la funcionalidad que hace la comparación.
Currificación
Currificación es el proceso de cambiar una función para que tome menos entradas (en este caso, transformar una función que realiza la división por cualquier número entero en uno que realiza la división por un entero ya establecido).
>>> def divide(x, y): ... return x / y >>> def divisor(d): ... return lambda x: divide(x, d) >>> mitad = divisor(2) >>> tercio = divisor(3) >>> print mitad(32), tercio(32) 16 10 >>> print mitad(40), tercio(40) 20 13
Si bien el uso de funciones anónimas quizás no es común en la currificación, de todas formas se puede utilizar. En el ejemplo anterior, el divisor de funciones genera funciones con un divisor especificado. Las funciones mitad y tercio currifican la división utilizando un divisor fijo. La función del divisor también forma una clausura al vincular la variable "d".
Funciones de orden superior
Python 2.x incluye varias funciones que toman funciones anónimas como argumento. Esta sección describe algunos de ellos.
Mapeo
La función de mapeo realiza una llamada de función en cada elemento de una lista. El siguiente ejemplo se aplica el cuadrado a cada elemento de una matriz con una función anónima.
>>> a = [1, 2, 3, 4, 5, 6] >>> print map(lambda x: x*x, a) [1, 4, 9, 16, 25, 36]
La función anónima acepta un argumento y lo multiplica por sí mismo (calcula su cuadrado). La forma anterior es desaconsejada por los desarrolladores del lenguaje, quienes sostienen que la forma presentada a continuación tiene el mismo significado y está más alineada con la filosofía del lenguaje:
>>> a = [1, 2, 3, 4, 5, 6] >>> print [x*x for x in a] [1, 4, 9, 16, 25, 36]
Filtro
La función de filtro devuelve todos los elementos de una lista que al ser evaluados utilizando una determinada función regresan True
.
>>> a = [1, 2, 3, 4, 5, 6] >>> print filter(lambda x: x % 2 == 0, a) [2, 4, 6]
La función anónima comprueba si el argumento que se le pasa es par. La solución utilizando la estrategia de mapeo a continuación se considera más apropiado:
>>> a = [1, 2, 3, 4, 5, 6] >>> print [x for x in a if x % 2 == 0] [2, 4, 6]
Doblar
La función de doblar / reducir se ejecuta sobre todos los elementos de una lista (normalmente de izquierda a derecha), acumulando un valor a medida que pasa. Un uso común de esto es combinar todos los elementos de una lista en un valor, por ejemplo:
>>> a = [1, 2, 3, 4, 5] >>> print reduce(lambda x,y: x*y, a) 120
Esto realiza:
La función anónima aquí es la multiplicación de los dos argumentos. El resultado de una función doblar debe ser más de un solo valor. En su lugar, tanto el mapa como el filtro pueden crearse utilizando la función doblar. En el mapeo, el valor que se acumula es una nueva lista, que contiene los resultados de aplicar una función a cada elemento de la lista original. En el filtro, el valor que se acumula es una nueva lista que contiene solo los elementos que coinciden con la condición dada.
Lista de lenguajes
A continuación se muestra una lista de los lenguajes de programación más populares que admiten funciones anónimas totalmente, parcialmente como alguna variante, o no lo admiten en lo absoluto. Esta tabla muestra algunas tendencias generales. En primer lugar, los idiomas que no admiten funciones anónimas (C, Pascal, Object Pascal) son todos lenguajes estatisticamente tipificados convencionales. Sin embargo, los lenguajes de tipo estático pueden admitir funciones anónimas. Por ejemplo, los lenguajes de marcas están escritos de forma estática y además incluyen funciones anónimas, y Delphi, un dialecto de Object Pascal, se ha extendido para soportar funciones anónimas. En segundo lugar, los idiomas que tratan las funciones como funciones de primera clase (Dylan, Haskell, JavaScript, Lisp, Lenguaje de marcado, Perl, Python, Ruby, Scheme) generalmente tienen soporte de funciones anónimas para que las funciones se puedan definir y pasar tan fácilmente como otros tipos de datos. Sin embargo, el nuevo estándar C++ 11 los añade a C++, a pesar de que este es un lenguaje convencional estáticamente tipado.
Tabla con los lenguajes y sus soportes | ||
---|---|---|
Lenguaje | Soporte | Notas |
ActionScript | ![]() ![]() | |
Ada | ![]() ![]() | Las funciones de expresión forman parte de Ada2012 |
ALGOL 68 | ![]() ![]() | |
Brainfuck | ![]() ![]() | |
Bash | ![]() ![]() | Se ha creado una biblioteca para admitir funciones anónimas en Bash.[4] |
C | ![]() ![]() | El apoyo se proporciona en Clang y junto con el compilador-rt lib LLVM. El apoyo de GCC se da para una implementación de macros que permite la posibilidad de uso. |
C# | ![]() ![]() | |
C++ | ![]() ![]() | Como parte del estándar C++11. |
CFML | ![]() ![]() | A partir de Railo 4[5] ColdFusion 10[6] |
Clojure | ![]() ![]() | |
COBOL | ![]() ![]() | Micro Focus es un lenguaje COBOL gestionado no estpándar el cual soporta lambdas, a los cuales se les llaman delegados / métodos anónimos.[7] |
Curl | ![]() ![]() | |
D | ![]() ![]() | |
Dart | ![]() ![]() | |
Delphi | ![]() ![]() | |
Dylan | ![]() ![]() | |
Eiffel | ![]() ![]() | |
Elixir | ![]() ![]() | |
Erlang | ![]() ![]() | |
F# | ![]() ![]() | |
Factor | ![]() ![]() | Las "Citas" soportan esta función.[8] |
Fortran | ![]() ![]() | |
Frink | ![]() ![]() | |
Go | ![]() ![]() | |
Gosu | ![]() ![]() | |
Groovy | ![]() ![]() | |
Haskell | ![]() ![]() | |
Haxe | ![]() ![]() | |
Java | ![]() ![]() | Supported in Java 8. Ver la sección limitaciones en Java para detalles. |
JavaScript | ![]() ![]() | |
Julia | ![]() ![]() | |
Lisp | ![]() ![]() | |
Logtalk | ![]() ![]() | |
Lua | ![]() ![]() | |
MUMPS | ![]() ![]() | |
Mathematica | ![]() ![]() | |
Maple | ![]() ![]() | |
MATLAB | ![]() ![]() | |
Maxima | ![]() ![]() | |
OCaml | ![]() ![]() | |
Octave | ![]() ![]() | |
Object Pascal | ![]() ![]() | Delphi, un dialecto de Object Pascal, soporta funciones anónimas (formalmente llamados métodos anónimos ) de forma nativa desde Delphi 2009. El dialecto Pascal llamado Oxygene también los soporta. |
Objective-C (Mac OS X 10.6+) | ![]() ![]() | Son llamados bloques; en adición a Objective-C, los bloques también pueden ser usados en C and C++ cuando se programa dentro de la plataforma Apple. |
Pascal | ![]() ![]() | |
Perl | ![]() ![]() | |
PHP | ![]() ![]() | A partir de PHP 5.3.0, se admiten funciones verdaderamente anónimas. Anteriormente, solo se admitían funciones anónimas parciales, que funcionaban como la implementación de C#. |
PL/I | ![]() ![]() | |
Python | ![]() ![]() | Python soporta funciones anónimas a través de la sintaxis lambda, que soporta solo expresiones, no declaraciones. |
R | ![]() ![]() | |
Racket | ![]() ![]() | |
Rexx | ![]() ![]() | |
RPG | ![]() ![]() | |
Ruby | ![]() ![]() | Las funciones anónimas de Ruby, heredadas de Smalltalk, se llaman bloques. |
Rust | ![]() ![]() | |
Scala | ![]() ![]() | |
Scheme | ![]() ![]() | |
Smalltalk | ![]() ![]() | Las funciones anónimas de Smalltalk se llaman bloques. |
Standard ML | ![]() ![]() | |
Swift | ![]() ![]() | Las funciones anónimas de Swiftson son llamadas clausuras. |
TypeScript | ![]() ![]() | |
Tcl | ![]() ![]() | |
Vala | ![]() ![]() | |
Visual Basic .NET v9 | ![]() ![]() | |
Visual Prolog v 7.2 | ![]() ![]() | |
Wolfram | ![]() ![]() |
Ejemplos
Numerosos idiomas soportan funciones anónimas, o son capaces de realizar alguna función similar.
C (extensión no estándar)
La función anónima no es compatible con el lenguaje de programación C estándar, pero es soportada por algunas variables de C, como GCC y Clang.
GCC
El GNU Compiler Collection (colección de compiladores GNU) (GCC) admite funciones anónimas, mezcladas con funciones anidadas y expresiones de sentencia. Tiene la forma:
( { Tipo_de_retorno Nombre_de_la_función_anónima(parámetros) { cuerpo_de_la_función} Nombre_de_la_función_anónima; } )
El siguiente ejemplo funciona solo con GCC. Debido a cómo se expanden las macros, l_body
no puede contener comas fuera de los paréntesis; GCC trata la coma como un delimitador entre argumentos de macro. El argumento l_ret_type
puede eliminarse si está disponible __typeof__
; En el ejemplo siguiente al usar __typeof__
en un array, este devolverá testtype *
, el cual puede ser dereferenciado para el valor real en caso de ser necesario.
#include <stdio.h> //* Esta es la definición de una función anónima */ #define lambda(l_ret_type, l_arguments, l_body) \ ({ \ l_ret_type l_anonymous_functions_name l_arguments \ l_body \ &l_anonymous_functions_name; \ }) #define forEachInArray(fe_arrType, fe_arr, fe_fn_body) \ { \ int i=0; \ for(;i<sizeof(fe_arr)/sizeof(fe_arrType);i++) { fe_arr[i] = fe_fn_body(&fe_arr[i]); } \ } typedef struct __test { int a; int b; } testtype; void printout(const testtype * array) { int i; for ( i = 0; i < 3; ++ i ) printf("%d %d\n", array[i].a, array[i].b); printf("\n"); } int main(void) { testtype array[] = { {0,1}, {2,3}, {4,5} }; printout(array); /* La función anónima se da como función para el foreach */ forEachInArray(testtype, array, lambda (testtype, (void *item), { int temp = (*( testtype *) item).a; (*( testtype *) item).a = (*( testtype *) item).b; (*( testtype *) item).b = temp; return (*( testtype *) item); })); printout(array); return 0; }
Clang (C, C++, Objective-C, Objective-C++)
Clang soporta funciones anónimas, son llamadas bloques, los cuales tienen la forma:
^return_type ( parameters ) { function_body }
El tipo de los bloques anteriores es return_type (^)(parameters)
. Utilizando la extensión de "bloques" anteriormente mencionada y el Grand Central Dispatch (libdispatch), el código podría parecer más simple:
#include <stdio.h> #include <dispatch/dispatch.h> int main(void) { void (^count_loop)() = ^{ for (int i = 0; i < 100; i++) printf("%d\n", i); printf("ah ah ah\n"); }; /* Se pasa como parámetro a otra función */ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), count_loop); /* Se invoca directamente */ count_loop(); return 0; }
El código con bloques debe ser compilado con el parámetro -fblocks
y enlazado con -lBlocksRuntime
.
C++ (desde C++11)
C++11 soporta funciones anónimas, llamadas expresiones lambda , que tienen la forma:
[capture](parameters) -> return_type { function_body }
Un ejemplo de función lambda se define de la siguiente forma:
[](int x, int y) -> int { return x + y; }
C++11 también soporta clausuras.Las clausuras se definen entre corchetes ([
y ]
) en la declaración de la expresión lambda. El mecanismo permite que estas variables sean capturadas por valor o por referencia. La siguiente tabla muestra esto:
[] //Sin variables definidas. Intentar utilizar cualquier variable externa en el lambda es un error. [x, &y] //x se captura por valor, y se captura por referencia [&] //Cualquier variable externa es capturada implícitamente por referencia si se utiliza [=] //Cualquier variable externa es capturada implícitamente por valor si se utiliza [&, x] //x se captura explícitamente por valor. Otras variables serán capturadas por referencia [=, &z] //z se captura explícitamente por referencia. Otras variables serán capturadas por el valor
Las variables capturadas por valor son constantes por defecto. Agregar mutable
después de la lista de parámetros hace que no sean constantes. Los dos ejemplos siguientes demuestran el uso de una expresión lambda:
std::vector<int> some_list{ 1, 2, 3, 4, 5 }; int total = 0; std::for_each(begin(some_list), end(some_list), [&total](int x) { total += x; });
Esto calcula el total de todos los elementos de la lista. La variable total
se almacena como parte de la clausura de la función lambda. Puesto que es una referencia a la variable stack total
, esta puede cambiar su valor.
std::vector<int> some_list{ 1, 2, 3, 4, 5 }; int total = 0; int value = 5; std::for_each(begin(some_list), end(some_list), [&, value, this](int x) { total += x * value * this->some_func(); });
Esto hará que total
sea almacenado como referencia, pero value
será almacenado como una copia. La captura de this
es especial. Solo se puede capturar por valor, no por referencia. this
solo se puede capturar si la función de clausura más cercana es una función de tipo no estática. La expresión lambda tendrá el mismo acceso que el miembro que lo creó, en términos de miembros protegidos y privados. Si this
es capturado, ya sea explícita o implícitamente, también se comprueba el alcance de los miembros de clase incluidos. Acceder a los miembros de this
no necesita el uso explícito de la sintaxis this ->
.
La implementación interna específica puede variar, pero la expectativa es que una función lambda que capture todo por referencia almacenará el puntero de pila real de la función en la que se crea, en lugar de referencias individuales a las variables de pila. Sin embargo, debido a que la mayoría de las funciones lambda son pequeñas y locales en el ámbito, son candidatos probables para expansión inline, y por lo tanto no necesitan almacenamiento añadido para las referencias.
Si se invoca un objeto de clausura que contiene referencias a variables locales después del alcance del bloque más interno de su creación, el comportamiento es indefinido.
Las funciones Lambda son objetos de función de un tipo dependiente de la implementación; El nombre de este tipo solo está disponible para el compilador. Si el usuario desea tomar una función lambda como un parámetro, el tipo debe ser una plantilla, o debe crear un std::function
o un objeto similar para capturar el valor lambda. El uso de la palabra clave auto
puede ayudar a almacenar la función lambda
auto my_lambda_func = [&](int x) { /*...*/ }; auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });
A continuación se muestra un ejemplo de almacenamiento de funciones anónimas en variables, vectores y matrices; Y pasarlos como parámetros nombrados:
#include <functional> #include <vector> #include <iostream> double eval(std::function <double(double)> f, double x = 2.0) { return f(x); } int main() { std::function<double(double)> f0 = [](double x){return 1;}; auto f1 = [](double x){return x;}; decltype(f0) fa[3] = {f0,f1,[](double x){return x*x;}}; std::vector<decltype(f0)> fv = {f0,f1}; fv.push_back ([](double x){return x*x;}); for(int i=0;i<fv.size();i++) std::cout << fv[i](2.0) << std::endl; for(int i=0;i<3;i++) std::cout << fa[i](2.0) << std::endl; for(auto &f : fv) std::cout << f(2.0) << std::endl; for(auto &f : fa) std::cout << f(2.0) << std::endl; std::cout << eval(f0) << std::endl; std::cout << eval(f1) << std::endl; std::cout << eval([](double x){return x*x;}) << std::endl; return 0; }
Una expresión lambda con una especificación de captura vacía ([]
) puede ser convertida implícitamente en un puntero de función con el mismo tipo que el lambda. Así que esto es legal:
auto a_lambda_func = [](int x) { /*...*/ }; void (* func_ptr)(int) = a_lambda_func; func_ptr(4); //llama a la expresión lambda.
Las bibliotecas Boost también proporcionan su propia sintaxis para las funciones lambda, utilizando la siguiente sintaxis:[11]
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
D
D utiliza delegados en línea para implementar funciones anónimas. La sintaxis completa para un delegado en línea es:
return_type delegate(arguments){/*body*/}
Si no es ambiguo, se puede omitir el tipo de retorno y la palabra clave delegate.
(x){return x*x;} delegate (x){return x*x;} // Si se necesita más verbosidad (int x){return x*x;} // Si no se puede inferir el tipo de parámetro delegate (int x){return x*x;} // ditto delegate double(int x){return x*x;} // Si el tipo de retorno debe ser forzado manualmente
Desde la versión 2.0, D asigna clausuras en la pila a menos que el compilador pueda probar que es innecesario; La palabra clave scope
se puede utilizar para forzar la asignación de pila. Desde la versión 2.058, es posible utilizar la notación abreviada:
x => x*x; (int x) => x*x; (x,y) => x*y; (int x, int y) => x*y;
Una función anónima puede asignarse a una variable y utilizarse de la siguiente manera:
auto sqr = (double x){return x*x;}; double y = sqr(4);
Dart
Dart permite funciones anónimas en la siguiente forma:
var sqr = (x) => x * x; print(sqr(5));
o
print(((x) => x * x)(5));
Delphi
Delphi introdujo funciones anónimas desde la versión 2009.
program demo; type TSimpleProcedure = reference to procedure; TSimpleFunction = reference to function(x: string): Integer; var x1: TSimpleProcedure; y1: TSimpleFunction; begin x1 := procedure begin Writeln('Hello World'); end; x1; //Invocar el método anónimo recién definido y1 := function(x: string): Integer begin Result := Length(x); end; Writeln(y1('bar')); end.
Elixir
Elixir usa las clausuras (fn
) para designar funciones anónimas.
sum = fn(a, b) -> a + b end sum.(4, 3) #=> 7 square = fn(x) -> x * x end Enum.map [1, 2, 3, 4], square #=> [1, 4, 9, 16]
Erlang
Erlang utiliza una sintaxis para funciones anónimas similar a la de las funciones nombradas.
% Función anónima vinculada a la variable "Square" Square = fun(X) -> X * X end. % Función nombrada con la misma funcionalidad square(X) -> X * X.
Go
Go soporta funciones anónimas.
foo := func(x int) int { return x * x } fmt.Println(foo(10))
Haskell
Haskell usa una sintaxis concisa para funciones anónimas (expresiones lambda).
\x -> x * x
Las expresiones Lambda están totalmente integradas con el motor de inferencia de tipo, y soportan toda la sintaxis y características de las funciones "ordinarias" (excepto el uso de múltiples definiciones para la correspondencia de patrones, ya que la lista de argumentos solo se especifica una vez).
map (\x -> x * x) [1..5] -- returns [1, 4, 9, 16, 25]
Las siguientes expresiones son todas equivalentes:
f x y = x + y f x = \y -> x + y f = \x y -> x + y
Haxe
En Haxe, las funciones anónimas son llamadas expresiones lambda, y utilizan la sintaxis (argumento-lista) expresión;
.
var f = function(x) return x*x; f(8); // 64 (function(x,y) return x+y)(5,6); // 11
Java
Java desde el JDK 8 soporta funciones anónimas, denominadas Expresiones Lambda.[12] Una expresión lambda consiste en una lista separada por comas de los parámetros formales encerrados entre paréntesis, un símbolo de flecha (->) y un cuerpo. Los tipos de datos de los parámetros siempre se pueden omitir, al igual que los paréntesis si solo hay un parámetro. El cuerpo puede consistir en una sentencia o un bloque de sentencia.[13]
// sin parámetros () -> System.out.println("Hello, world.") // Con un parámetro (este ejemplo es una función de identidad). a -> a // Con una expresión (a, b) -> a + b // Con información de tipo explícita (long id, String name) -> "id: " + id + ", name:" + name // Con un bloque de código (a, b) -> { return a + b; } // Con múltiples afirmaciones en el cuerpo lambda. Necesita un bloque de código. // Este ejemplo también incluye dos expresiones lambda anidadas (la primera también es una clausura). (id, defaultPrice) -> { Optional<Product> product = productList.stream().filter(p -> p.getId() == id).findFirst(); return product.map(p -> p.getPrice()).orElse(defaultPrice); }
Las expresiones Lambda se convierten en "interfaces funcionales" (definidas como interfaces que contienen solo un método abstracto además de uno o más métodos predeterminados o estáticos[13]), como en el ejemplo siguiente:
public class Calculator { interface IntegerMath { int operation(int a, int b); default IntegerMath swap() { return (a, b) -> operation(b, a); } } private static int apply(int a, int b, IntegerMath op) { return op.operation(a, b); } public static void main(String... args) { IntegerMath addition = (a, b) -> a + b; IntegerMath subtraction = (a, b) -> a - b; System.out.println("40 + 2 = " + apply(40, 2, addition)); System.out.println("20 - 10 = " + apply(20, 10, subtraction)); System.out.println("10 - 20 = " + apply(20, 10, subtraction.swap())); } }
En este ejemplo, se declara una interfaz funcional denominada IntegerMath
. Las expresiones Lambda que implementan IntegerMath
se pasan al método apply()
para ejecutarse. Los métodos predeterminados como swap
definen métodos en funciones. Java 8 introdujo otro mecanismo denominado referencia de método (el operador ::) para crear una expresión lambda en un método existente. Una referencia de método no indica el número o los tipos de argumentos porque estos se extraen del método abstracto de la interfaz funcional.
IntBinaryOperator sum = Integer::sum;
En el ejemplo anterior, la interfaz funcional IntBinaryOperator
declara un método abstracto int applyAsInt(int, int)
, por lo que el compilador busca un método int sum(int, Int)
en la clase java.lang.Integer
.
Limitaciones en Java
Las expresiones lambda en Java 8 poseen las siguientes limitaciones:
- Las expresiones lambda pueden regresar excepciones comprobadas, pero tales lambdas no funcionarán con las interfaces utilizadas por la API de la colección.
- Las variables que están dentro del alcance donde se declara el lambda solo se pueden acceder dentro del lambda si son efectivamente finales, es decir, si la variable no está mutada dentro o fuera del ámbito lambda.
JavaScript
JavaScript/ECMAScript permite el uso de funciones anónimas.
alert((function(x){ return x*x; })(10));
En ES6:
alert((x => x*x)(10));
Esta construcción se utiliza a menudo en Bookmarklets. Por ejemplo, para cambiar el título del documento actual (visible en la barra de título de su ventana] a su URL, el siguiente bookmarklet puede parecer que funciona.
javascript:document.title=location.href;
Sin embargo, como la sentencia de asignación devuelve un valor (la propia URL), muchos navegadores crean una nueva página para mostrar este valor. En su lugar, una función anónima, que no devuelve un valor, se puede utilizar:
javascript:(function(){document.title=location.href;})();
La sentencia de la función en el primer par de paréntesis (el paréntesis más externo) declara una función anónima, que se ejecuta cuando se utiliza con el último par de paréntesis. Esto es casi equivalente a lo siguiente, que puebla el entorno con f
a diferencia de una función anónima.
javascript:var f = function(){document.title=location.href;}; f();
Se utilizan "Bookmarklets" para evitar nuevas páginas para funciones anónimas arbitrarias: La sentencia de función en el primer par de paréntesis (el más externo) declara una función anónima, que se ejecuta cuando se utiliza con el último par de paréntesis. Esto es casi equivalente a lo siguiente, que completa el entorno con f
a diferencia de una función anónima.
javascript:var f = function(){document.title=location.href;}; f();
Uso de "Bookmarklets" para evitar crear nuevas páginas para funciones anónimas arbitrarias:
javascript:void(function(){return document.title=location.href;}());
O simplemente:
javascript:void(document.title=location.href);
JavaScript posee ciertas sutilezas sintácticas para la semántica de definir, invocar y evaluar funciones anónimas. Estos matices subliminales son una consecuencia directa de la evaluación de las expresiones entre paréntesis. Las siguientes construcciones que se llaman expresiones de funciones inmediatamente invocadas ilustran esto:
(function(){ ... }())
y
(function(){ ... })()
representando "function(){ ... }
" por f
La forma de los constructores son un entre paréntesis dentro de un entre paréntesis (f())
y un entre paréntesis aplicado a un entre paréntesis (f)()
. Hay que observar que la ambigüedad sintáctica general de una expresión entre paréntesis, argumentos entre paréntesis a una función y los paréntesis alrededor de los parámetros formales en una definición de función. En particular, JavaScript define el operador ,
en el contexto de una expresión entre paréntesis. No es mera coincidencia que las formas sintácticas coincidan para una expresión y los argumentos de una función (ignorando la función de la sintaxis del parámetro formal). Si f
no se identifica en las construcciones anteriores, estas se convierten en (())
y ()()
. La primera no proporciona ninguna pista sintáctica de ninguna función residente, pero la segunda debe evaluar la primera entre paréntesis como una función para ser JavaScript legal. El ()
podría ser ([], {}, 42, "abc", function() {}) siempre que la expresión se evalúe como una función. Además, una función es una instancia de objeto (de la misma manera los objetos son instancias de función) y los corchetes de notación de literal de objeto ({}
) se utilizan para definir código reforzado, (en contraposición a usar new Function(...)
). En un sentido muy amplio no riguroso (especialmente desde que los enlaces globales están comprometidos), una secuencia arbitraria de afirmaciones reforzadas de JavaScript, {cosas}
, puede ser considerada un punto fijo de:
(function(){( function(){( ... {( function(){cosas}() )} ... )}() )}() )
También, se puede escribir más correctamente, pero con precaución de la siguiente forma:
( function(){stuff}() ) ~= A_Fixed_Point_of( function(){ return function(){ return ... { return function(){stuff}() } ... }() }() )
Hay que observar las implicaciones de la función anónima en los fragmentos de JavaScript que siguen:
function(){ ... }()
sin rodear()
- generalmente no es válido(f=function(){ ... })
No "olvida" af
globalmente, a diferencia de(function f(){ ... })
- El rendimiento de las métricas para analizar las complejidades de espacio y tiempo de las llamadas de función, pila de llamadas, etc. en un motor JavaScript intérprete se puede implementar fácilmente con estas últimas construcciones de función anónimas. A partir de las implicaciones de los resultados, es posible deducir algunos de los detalles de implementación de un motor recursivo versus uno iterativo, especialmente la recursión de cola.
Julia
En el lenguaje de programación Julia se definen las funciones anónimas utilizando la sintaxis (arguments)->(expression)
,
julia> f = x -> x*x; f(8) 64 julia> ((x,y)->x+y)(5,6) 11
Lisp
Lisp y Scheme soportan funciones anónimas utilizando la construcción "lambda", que es una referencia al cálculo lambda. Clojure soporta funciones anónimas con la forma especial fn
y la sintaxis del lector #()
.
(lambda (arg) (* arg arg))
Common Lisp
Common Lisp tiene el concepto de expresiones lambda. Una expresión lambda se escribe como una lista con el símbolo "lambda" como su primer elemento. La lista contiene entonces la lista de argumentos, la documentación o las declaraciones y un cuerpo de función. Las expresiones lambda se pueden utilizar dentro de las formas lambda y con el operador especial function
.
(function (lambda (arg) (do-something arg)))
Function
se puede abreviar como #
. Además, existe la macro lambda, que se expande en una función de forma:
; usando "#" #'(lambda (arg) (haz-algo argumento)) ; usando la macro "lambda": (lambda (arg) (haz-algo argumento))
Un uso típico de funciones anónimas en Common Lisp es pasarlas a funciones de orden superior como "mapcar", que aplica una función a cada elemento de una lista y devuelve una lista de los resultados.
(mapcar #'(lambda (x) (* x x)) '(1 2 3 4)) ; -> (1 4 9 16)
La forma lambda en Common Lisp permite que una expresión lambda se escriba en una llamada de función:
((lambda (x y) (+ (sqrt x) (sqrt y))) 10.0 12.0)
También es posible dar nombres globales más adelante a las funciones anónimas en Common Lisp:
(setf (symbol-function 'sqr) (lambda (x) (* x x))) ; which allows us to call it using the name SQR: (sqr 10.0)
Scheme
Curiosamente, en Scheme (lenguaje de programación), las funciones nombradas son simplemente "azúcar sintáctico" para funciones anónimas vinculadas a nombres:
(define (Algún-nombre argumento) (haz-algo argumento))
Se expande (y es equivalente) a:
(define Algún-nombre (lambda (argumento) (haz-algo argumento)))
Clojure
Clojure soporta funciones anónimas a través de la forma especial "fn":
(fn [x] (+ x 3))
También hay una sintaxis de lector para definir un lambda:
# (+ % %2%3) ; Define una función anónima que toma tres argumentos y los suma..
Al igual que Scheme, las "funciones nombradas" de Clojure son simplemente "azúcar sintáctico" para las lambdas vinculadas a los nombres:
(defn func [arg] (+ 3 arg))
Se expande a:
(def func (fn [arg] (+ 3 arg)))
Lua
En Lua (al igual que Scheme) todas las funciones son anónimas. Una "función nombrada" en Lua es simplemente una variable que contiene una referencia a un objeto de función.[14]
Así, en Lua:
function foo(x) return 2*x end
Es simple azúcar sintáctico para:
foo = function(x) return 2*x end
Un ejemplo de uso de funciones anónimas para ordenar en orden inverso:
table.sort(network, function(a,b) return a.name > b.name end)
Las funciones anónimas son importantes en Mathematica. Hay varias maneras de crearlas. A continuación se muestran algunas funciones anónimas que incrementan un número. La primera es la más común. #1
hace referencia al primer argumento y &
marca el final de la función anónima
#1+1& Function[x,x+1] x \[Function] x+1
Así, por ejemplo:
f:= #1^2&;f[8] 64 #1+#2&[5,6] 11
Además, Mathematica posee una construcción añadida para realizar funciones anónimas recursivas. El símbolo #0
se refiere a toda la función. La siguiente función calcula el factorial de su entrada:
If[#1 == 1, 1, #1 * #0[#1-1]]&
MATLAB, Octave
Las funciones anónimas en MATLAB o Octave se definen mediante la sintaxis @(argumento-lista)expresión
. Las variables que no se encuentran en la lista de argumentos se heredan del ámbito de inclusión.
> f = @(x)x*x; f(8) ans = 64 > (@(x,y)x+y)(5,6) % Solamente funciona en Octave ans = 11
Maxima
En Maxima se definen funciones anónimas utilizando la sintaxis lambda(argumento-lista,expresión)
:
f: lambda([x],x*x); f(8); 64 lambda([x,y],x+y)(5,6); 11
ML
Los diversos dialectos de ML (lenguaje de programación) admiten funciones anónimas.
OCaml
OCaml admite funciones anónimas de la siguiente forma:
fun arg -> arg * arg
F#
F# admite funciones anónimas, de la siguiente manera:
(fun x -> x * x) 20 // 400
Standard ML
Standard ML admite funciones anónimas, de la siguiente manera:
fn arg => arg * arg
Perl
Perl 5
Perl 5 admite funciones anónimas, en la siguiente forma:
(sub { print "Fui llamado\n" })->(); # 1. Completamente anónimo, llamado en cuanto fue creado my $squarer = sub { my $x = shift; $x * $x }; # 2. Asignado a una variable sub curry { my ($sub, @args) = @_; return sub { $sub->(@args, @_) }; # 3. Como un valor de retorno de otra función } # Ejemplo de currificación en Perl sub sum { my $tot = 0; $tot += $_ for @_; $tot } # retorna la suma de sus argumentos my $curried = curry \&sum, 5, 7, 9; print $curried->(1,2,3), "\n"; # muestra 27 ( = 5 + 7 + 9 + 1 + 2 + 3 )
Otras construcciones toman "bloques desnudos" como argumentos, que sirven una función similar a las funciones lambda de un parámetro, pero no tienen la misma convención de paso de parámetros que las funciones. -- @_ no está establecido.
my @cuandrados = map { $_ * $_ } 1..10; # Map y grep no utilizan la palabra clave 'sub' my @cuadrado2 = map $_ * $_, 1..10; # Paréntesis innecesarios para una expresión my @ejemplo_incorrecto = map { print for @_ } 1..10; # Valores no son pasados como una función normal de Perl
Perl 6
En Perl 6, todos los bloques (incluso aquellos asociados con if, while, etc.) son funciones anónimas. Se ejecuta inmediatamente un bloque que no se utiliza como valor rvalue.
# Completamente anónimo, es llamado en cuanto se crea { say "Fui llamado" };
# Asignado a una variable my $squarer1 = -> $x { $x * $x }; # 2a. Pointy block (expresión lambda) my $squarer2 = { $^x * $^x }; # 2b. twigil my $squarer3 = { my $x = shift @_; $x * $x }; # 2b. Estilo de Perl 5
# Currificación sub suma ($m, $n) { $m + $n } my $siete = suma(3, 4); my $suma_uno = &suma.assuming(m => 1); my $ocho = $suma_uno($siete);
PHP
Antes de la versión 4.0.1, PHP no tenía soporte para funciones anónimas.[15]
PHP 4.0.1 a 5.3
PHP 4.0.1 introdujo la llamada create_function
que inicialmente era cual soportaba las funciones anónimas. Esta llamada de función crea una nueva función con nombre aleatorio y devuelve su nombre como una cadena de texto.
$foo = create_function('$x', 'return $x*$x;'); $bar = create_function("\$x", "return \$x*\$x;"); echo $foo(10);
La lista de argumentos y el cuerpo de funciones deben estar en comillas simples, o en su defecto, los signos de dólar deben escaparse. De lo contrario, PHP asume que "$x
" significa la variable $x
y la sustituirá (a pesar de que posiblemente no exista) en la cadena. Para funciones con comillas o funciones de muchas variables, puede ser muy tedioso asegurarse que el cuerpo de la función prevista es lo que PHP interpreta.
En el ejemplo anterior, cada invocación de create_function
crea una nueva función, la cual existe para el resto del programa, y no puede ser recolectada como basura, haciendo que ocupe memoria de forma irreversible en el programa. Si este método se utiliza para crear funciones anónimas muchas veces, por ejemplo, dentro de un bucle, puede causar gaves problemas de memoria.
PHP 5.3
PHP 5.3 agregó una nueva clase llamada Closure
y el "método mágico" __invoke()
que hace invocable una instancia de clase.[16]
$x = 3; $func = function($z) { return $z *= 2; }; echo $func($x); // Muestra "6" en la salida
En el ejemplo anterior, $func
es una instancia de Closure
y echo$ func()
equivale a $func->__invoke $ Z)
PHP 5.3 imita las funciones anónimas, pero no admite funciones verdaderamente anónimas porque las funciones de PHP no son objetos de primera clase.
PHP 5.3 soporta clausuras pero las variables deben ser explícitamente indicadas como tales:
$x = 3; $func = function() use(&$x) { $x *= 2; }; $func(); echo $x; // Muestra "6" en la salida
La variable $x
está enlazada por referencia para al invocar $func
este lo modifique y los cambios sean visibles fuera de la función.
Dialectos de Prolog
Logtalk
Logtalk utiliza la siguiente sintaxis para expresiones anónimas (expresiones lambda):
{FreeVar1, FreeVar2, ...}/[ParametroLambda1, ParametroLambda2, ...]>>Goal
Un ejemplo simple sin variables libres y usando un predicado de asignación de listas sería:
| ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys). Ys = [2,4,6] yes
La currificación también es soportada. Es posible escribir el ejemplo anterior como:
| ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys). Ys = [2,4,6] yes
Visual Prolog
Las funciones anónimas (en general los "predicados" anónimos) se introdujeron en la versión 7.2. de Visual Prolog.[17] Los predicados anónimos pueden capturar valores desde el contexto. Si se crea el predicado en un miembro de objeto, este también puede acceder al estado del objeto (captando This
), mkAdder
devuelve una función anónima, que ha capturado el argumento X
en el cierre. La función devuelta es una función que añade X
a su argumento:
clauses mkAdder(X) = { (Y) = X+Y }.
Python
Python soporta funciones anónimas simples a través de la forma lambda. El cuerpo ejecutable del lambda debe ser una expresión y no puede ser una declaración, la cual es una restricción que limita su utilidad. El valor devuelto por el lambda es el valor de la expresión que está contenida en esta. Las formas Lambda se pueden utilizar en cualquier lugar donde puedan funcionar las funciones ordinarias. Sin embargo, estas restricciones hacen que sea una versión muy limitada de una función normal. Por ejemplo:
>>> foo = lambda x: x*x >>> print(foo(10)) 100
En general, las convenciones de Python fomentan el uso de funciones nombradas definidas en el mismo ámbito que uno podría utilizar normalmente funciones anónimas en otros idiomas. Esto es aceptable ya que las funciones definidas localmente implementan todo el poder de las clausuras y son casi tan eficientes como el uso de un lambda en Python.
En el siguiente ejemplo, se puede decir que la función "potencia" (pow
) ha sido modificada:
>>> def make_pow(n): ... def fixed_exponent_pow(x): ... return pow(x, n) ... return fixed_exponent_pow ... >>> sqr = make_pow(2) >>> print (sqr(10)) 100 >>> cub = make_pow(3) >>> print (cub(10)) 1000
R
En GNU R las funciones anónimas son definidas utilizando la sintaxis función(argumento-lista)expresión
como muestra el siguiente ejemplo:
> f <- function(x)x*x; f(8) [1] 64 > (function(x,y)x+y)(5,6) [1] 11
Ruby
Ruby soporta funciones anónimas utilizando una estructura sintáctica llamada bloque. Hay dos tipos de datos para bloques en Ruby:
- El tipo "
Proc
" el cual se comporta de forma similar a una clausura. - El tipo "
lambda
" el cual se comporta de forma más similar a una función anónima.[18]
Cuando se pasa a un método, en algunas circunstancias un bloque se convierte en un "Proc
".
irb(main):001:0> # Ejemplo 1: irb(main):002:0* # Funciones puramente anónimas utilizando bloques. irb(main):003:0* ex = [16.2, 24.1, 48.3, 32.4, 8.5] => [16.2, 24.1, 48.3, 32.4, 8.5] irb(main):004:0> ex.sort_by { |x| x - x.to_i } #Ordenar por parte fraccionaria, ignorando la parte entera. => [24.1, 16.2, 48.3, 32.4, 8.5] irb(main):005:0> # Ejemplo 2: irb(main):006:0* # Funciones de primera clase como un objeto explícito de Proc- irb(main):007:0* ex = Proc.new { puts "Hola mundo!" } => #<Proc:0x007ff4598705a0@(irb):7> irb(main):008:0> ex.call Hola mundo! => nil irb(main):009:0> # Ejemplo 3: irb(main):010:0* # Función que retorna una función lambda como objeto con parámetros irb(main):011:0* def is_multiple_of(n) irb(main):012:1> lambda{|x| x % n == 0} irb(main):013:1> end => nil irb(main):014:0> multiple_four = is_multiple_of(4) => #<Proc:0x007ff458b45f88@(irb):12 (lambda)> irb(main):015:0> multiple_four.call(16) => true irb(main):016:0> multiple_four[15] => false
Scala
En Scala, las funciones anónimas utilizan la siguiente sintaxis:[19]
(x: Int, y: Int) => x + y
En ciertos contextos, como cuando una función anónima es un parámetro que se pasa a otra función, el compilador puede inferir los tipos de los parámetros de la función anónima y se pueden omitir en la sintaxis. En tales contextos, también es posible utilizar una abreviatura para funciones anónimas que utilizan el carácter de subrayado para introducir parámetros sin nombre.
val list = List(1, 2, 3, 4) list.reduceLeft( (x, y) => x + y ) // Aquí, el compilador puede inferir que los tipos de x e y son Int. // Por lo tanto, no necesita anotaciones de tipo sobre los parámetros de la función anónima. list.reduceLeft( _ + _ ) // Cada subrayado representa un nuevo parámetro sin nombre en la función anónima. // Esto resulta en un equivalente aún más corto a la función anónima anterior.
Smalltalk
En Smalltalk las funciones anónimas son llamadas bloques y poseen la siguiente estructura:
[ :x | x*x ] value: 4 "returns 16"
Swift
En Swift, las funciones anónimas son llamadas clausuras,[20] y poseen la siguiente estructura:
{ (parameters) -> returnType in statement }
Por ejemplo:
{ (s1: String, s2: String) -> Bool in return s1 > s2 }
En aras de la brevedad y la expresividad, se pueden omitir los tipos de parámetro y el tipo de retorno si pueden inferirse:
{ s1, s2 in return s1 > s2 }
Del mismo modo, Swift también soporta declaraciones de devolución implícitas para cierres de una sola declaración:
{ s1, s2 in s1 > s2 }
Finalmente, los nombres de los parámetros también se pueden omitir; Cuando se omiten, se hace referencia a los parámetros utilizando nombres abreviados de argumentos, que consisten en el símbolo $ seguido de su posición (por ejemplo, $0, $1, $2, etc.):
{ $0 > $1 }
fn = function(){ // statements };
CFML admite cualquier declaración dentro de la definición de la función, no solamente expresiones, además CFML también admite funciones anónimas recursivas:
factorial = function(n){ return n > 1 ? n * factorial(n-1) : 1; };
Las funciones anónimas de CFML implementan clausuras.
.NET Framework
C#
En C#, el soporte para funciones anónimas se ha profundizado a través de varias versiones del compilador de idiomas. La versión 3.0 del lenguaje, lanzada en noviembre de 2007 junto a .NET Framework v3.5, soporta completamente las funciones anónimas. En C# son llamadas "expresiones lambda", siguiendo la versión original de funciones anónimas, el cálculo lambda.[21]
// El primer int es el tipo x // El segundo int es el tipo de retorno Func<int,int> foo = x => x*x; Console.WriteLine(foo(7));
Mientras la función sea anónima, no se puede asignar a una variable implícitamente tipada, ya que la sintaxis lambda podría ser una función anónima o un árbol de expresiones, y la elección no puede ser realizada automáticamente por el compilador. Por ejemplo, esto no funciona:
// esto NO compilará var foo = (int x) => x*x;
Sin embargo, una expresión lambda puede tomar parte en una inferencia de tipos y puede ser utilizada como un argumento de método, Por ejemplo, para utilizar funciones anónimas con la capacidad de mapeo usando System.Collections.Generic.List
(en el método ConvertAll()
):
// Inicializa la lista: var values = new List<int>() { 7, 13, 4, 9, 3 }; //Mapea las funciones anónimas sobre todos los elementos de una lista, retorna la nueva lista var foo = values.ConvertAll(d => d*d) ; // el resultado de la variable foo es del tipo System.Collections.Generic.List<Int32>
Las versiones anteriores de C# tenían un soporte más limitado para funciones anónimas. C# v1.0 (introducido en febrero de 2002 junto a .NET Framework v1.0) proporcionó soporte de función anónima parcial mediante el uso de delegados.
Esta construcción es similar a los delegados en PHP. En C# 1.0, los delegados son similares a punteros de funciones que hacen referencia a un método denominado explícitamente dentro de una clase. C# v2.0 (lanzado en noviembre de 2005 junto a .NET Framework v2.0) introdujo el concepto de métodos anónimos como una forma de escribir bloques de declaración sin nombre que se puedan ejecutar en una invocación delegada. C# 3.0 sigue permitiendo estas construcciones, pero también permite la construcción de expresiones lambda.
El siguiente ejemplo está diseñado para ser compilado en C# 3.0 y mostrará las tres formas en las que es posible escribir un método anónimo:
public class TestDriver { delegate int SquareDelegate(int d); static int Square(int d) { return d*d; } static void Main(string[] args) { // C# 1.0: Sintaxis delegada original necesaria // inicializando con un método nombrado SquareDelegate A = new SquareDelegate(Square); System.Console.WriteLine(A(3)); // C# 2.0: Un delegado puede inicializarse con // un código en línea, llamado "método anónimo". // Este método toma un int como un parámetro de entrada SquareDelegate B = delegate(int d) { return d*d; }; System.Console.WriteLine(B(5)); // C# 3.0. Un delegado puede inicializarse con // una expresión lambda. La expresión lambda toma un int y retorna otro int. // El tipo de x es inferido por el compilador. SquareDelegate C = x => x*x; System.Console.WriteLine(C(7)); // C# 3.0. Un delegado que acepta una entrada y devuelve una salida // también se puede declarar implícitamente con el tipo Func <>. System.Func<int,int> D = x => x*x; System.Console.WriteLine(D(9)); } }
En el caso de la versión 2.0 de C#, el compilador C# toma el bloque de código de la función anónima y crea una función privada estática. Internamente, la función recibe un nombre generado; Este nombre generado se basa en el nombre del método en el que se declara el Delegado. El nombre no está expuesto al código de la aplicación a menos que se utilice reflexión. En el caso de la versión 3.0 de C# , el mismo mecanismo es aplicado.
Visual Basic .NET
Visual Basic .NET 2008
Visual Basic .NET 2008 introdujo las funciones anónimas a través de la estructura lambda. Combinada con la escritura de tipos implícitos, VB provee una sintaxis sencilla para escribir funciones anónimas.En VB.NET 2008 las funciones anónimas deben ser definidas en una sola línea; no pueden ser expresiones compuestas. Además, una función anónima en VB.NET debe realmente una Function
de VB.NET, es decir, debe retornar un valor.
Dim Funcion_lambda = Function(x) x * x 'Crea la función de nombre "Funcion_lambda", la cual multiplica el argumento que se le pase por sí mismo. Console.WriteLine(Funcion_lambda(10)) 'Retorna 100 (10 x 10) 'Ya que el código no realiza una verificación del tipo de argumento que se pasa a "Funcion_lambda" 'en caso de que el tipo de argumento sea inválido, puede ocurrir una excepción en tiempo de ejecución.
Visual Basic .NET 2010
Desde Visual Basic .NET 2010 se es posible definir expresiones lambda multilíneas las cuales además ya no requieren que retornen algún valor. En el siguiente ejemplo se utiliza una función lambda multilinea para definir un Thread
.
Dim t As New System.Threading.Thread(Sub() For n as Integer = 0 to 10 'Cuenta hasta 10 Console.WriteLine(n) 'Imprime cada número Next End Sub) t.Start() 'Da la orden de que se ejecute el thread definido en la expresión lambda.
Es posible utilizar las expresiones lambda en VB.NET dentro de un Task
como un "Dispara y corre", permitiendo la ejecución de código de forma asíncrona dentro de un método sincronico.
Public Shared Variable1 As Integer Sub Run_tasks() For a As Integer = 0 To 9 Task.Run(Sub() 'Acá es posible realizar cualquier tarea que tome tiempo, esta se ejecuta en un thread distinto 'y no detiene el programa System.Threading.Thread.Sleep(100) 'Espera que pasen 100 milisegundos Variable1 = Variable1 + 1 End Sub) Next End Sub 'La subrutina se completa pero las tareas creadas siguen ejecutándose.
Véase también
Portal:Programación. Contenido relacionado con Programación.
Referencias
- ↑ «Funciones de orden superior — ¡Aprende Haskell por el bien de todos!». cs.famaf.unc.edu.ar. Archivado desde el original el 2 de junio de 2014. Consultado el 23 de febrero de 2020.
- ↑ Fernandez, Maribel (2009), Models of Computation: An Introduction to Computability Theory, Undergraduate Topics in Computer Science, Springer Science & Business Media, p. 33, ISBN 9781848824348, «The Lambda calculus ... was introduced by Alonzo Church in the 1930s as a precise notation for a theory of anonymous functions» .
- ↑ «Lecture 29: Fixpoints and Recursion». CS3110 Spring 2012 :: Data Structures and Functional Programming. Cornell University - Computer Science. Consultado el 3 de diciembre de 2014.
- ↑ «Bash lambda».
- ↑ ,«Closure support». Archivado desde el original el 6 de enero de 2014. Consultado el 10 de enero de 2017.
- ↑ «Whats new in ColdFusion 10». Archivado desde el original el 6 de enero de 2014. Consultado el 10 de enero de 2017.
- ↑ «Managed COBOL Reference». Micro Focus Documentation. Micro Focus. Consultado el 25 de febrero de 2014.
- ↑ «Quotations - Factor Documentation». Consultado el 26 de diciembre de 2015. «A quotation is an anonymous function (a value denoting a snippet of code) which can be used as a value and called using the Fundamental combinators.»
- ↑ «Gosu Documentation». Consultado el 4 de marzo de 2013.
- ↑ «Groovy Documentation». Archivado desde el original el 22 de mayo de 2012. Consultado el 29 de mayo de 2012.
- ↑ Järvi, Jaakko; Powell, Gary (n.d.). «Chapter 16. Boost.Lambda». Boost Documentation. Boost. Consultado el 22 de diciembre de 2014.
- ↑ http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
- ↑ a b The Java Tutorials: Lambda Expressions, docs.oracle.com
- ↑ «Programming in Lua - More about Functions». Archivado desde el original el 14 de mayo de 2008. Consultado el 25 de abril de 2008.
- ↑ http://php.net/create_function the top of the page indicates this with "(PHP 4 >= 4.0.1, PHP 5)"
- ↑ http://wiki.php.net/rfc/ Cierres
- ↑ «Predicados Anónimos». (enlace roto disponible en Internet Archive; véase el historial, la primera versión y la última).
- ↑ Sosinski, Robert (21 de diciembre de 2008). «Understanding Ruby Blocks, Procs and Lambdas». Reactive.IO. Archivado desde el original el 31 de mayo de 2014. Consultado el 30 de mayo de 2014.
- ↑ «Copia archivada». Archivado desde el original el 23 de julio de 2013. Consultado el 10 de enero de 2017.
- ↑ https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/Closures.html
- ↑ C# 4.0 Language Specification
Enlaces externos
- Anonymous Methods - When Should They Be Used? (blog about anonymous function in Delphi)
- Compiling Lambda Expressions: Scala vs. Java 8
- php anonymous functions php anonymous functions
- Lambda functions in various programming languages
Datos: Q567612