Articulo de referencia

Ejemplos de funciones anónimas

En programación informática , una función anónima ( literal de función , función lambda o bloque ) es una definición de función que no está vinculada a un identificador . Las fu...

En programación informática , una función anónima ( literal de función , función lambda o bloque ) es una definición de función que no está vinculada a un identificador . Las funciones anónimas suelen ser argumentos que se pasan a funciones de orden superior o se utilizan para construir el resultado de una función de orden superior que necesita devolver otra función. Si la función se usa solo una vez, o un número limitado de veces, una función anónima puede ser sintácticamente más ligera que usar una función con nombre. Las funciones anónimas son omnipresentes en los lenguajes de programación funcional y otros lenguajes con funciones de primera clase , donde cumplen la misma función para el tipo de función que los literales para otros tipos de datos .

Las funciones anónimas tienen su origen en la obra de Alonzo Church , quien inventó el cálculo lambda en 1936, antes de la llegada de las computadoras electrónicas, donde todas las funciones son anónimas. En varios lenguajes de programación, las funciones anónimas se introducen mediante la palabra clave `lambda` , y a menudo se las denomina lambdas o abstracciones lambda . Las funciones anónimas son una característica de los lenguajes de programación desde Lisp en 1958, y un número creciente de lenguajes de programación modernos las admiten. ( Artículo completo... )

Ejemplos de funciones anónimas

Numerosos lenguajes de programación admiten funciones anónimas o algo similar.

APL

Solo algunos dialectos admiten funciones anónimas, ya sea como dfns , en el estilo tácito o una combinación de ambos.

f ​​{ × } Como una dfn f 1 2 3 1 4 9 g ⊢× Como un tren tácito 3 ( fork ) g 1 2 3 1 4 9 h × Como una función tácita derivada h 1 2 3 1 4 9

C (extensión no estándar)

La función anónima no es compatible con el lenguaje de programación C estándar , pero sí con algunos dialectos de C, como GCC [ 1 ] y Clang .

GCC

La colección de compiladores GNU (GCC) admite funciones anónimas, combinadas con funciones anidadas y expresiones de sentencia. Tiene la siguiente forma:

( { return_type anonymous_functions_name ( parameters ) { function_body } anonymous_functions_name ; } )

El siguiente ejemplo solo funciona con GCC. Debido a cómo se expanden las macros, l_bodyno pueden contener comas fuera de los paréntesis; GCC trata la coma como un delimitador entre los argumentos de la macro. El argumento l_ret_typese puede eliminar si __typeof__está disponible; en el ejemplo siguiente, usar __typeof__en un array devolvería testtype *, que se puede desreferenciar para obtener el valor real si es necesario.

#include <stdio.h>// Esta es la definición de la 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 FOR_EACH_IN_ARRAY(fe_arrType, fe_arr, fe_fn_body) \ { \  for (int i = 0; i < sizeof(fe_arr) / sizeof(fe_arrType); i++) { \  fe_arr[i] = fe_fn_body(&fe_arr[i]); \  } \ }typedef struct { int a ; int b ; } IntegerPair ;void printElements ( const IntegerPair arr [], size_t n ) { for ( int i = 0 ; i < n ; ++ i ) { printf ( "%d %d \n " , arr [ i ]. a , arr [ i ]. b ); } }int main ( int argc , char * argv []) { IntegerPair pairArray [] = { { 0 , 1 }, { 2 , 3 }, { 4 , 5 } };printElements ( a , 3 ); // la función anónima se proporciona como función para el foreach FOR_EACH_IN_ARRAY ( IntegerPair , pairArray , lambda ( IntegerPair , ( void * item ), { int temp = ( * ( IntegerPair * ) item ).a ; ( * ( IntegerPair * ) item ) .a = ( * ( IntegerPair * ) item ) .b ; ( * ( IntegerPair * ) item ) .b = temp ; return ( * ( IntegerPair * ) item ) ; } ) ); printElements ( pairArray , 3 ); return 0 ; }

Clang (C, C++, Objective-C, Objective-C++)

Clang admite funciones anónimas, llamadas bloques , [ 2 ] que tienen la forma:

^ T ( parámetros ) { cuerpo }

El tipo de bloques de arriba es T (^)(params).

Utilizando la extensión de bloques mencionada anteriormente y Grand Central Dispatch (libdispatch), el código podría verse más simple:

#include <stdio.h> #include <dispatch/dispatch.h>int main ( int argc , char * argv []) { void ( ^ count_loop )() = ^ { for ( int i = 0 ; i < 100 ; i ++ ) { printf ( "%d \n " , i ); } printf ( "ah ah ah \n " ); };// Pasar como parámetro a otra función dispatch_async ( dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ), count_loop );// Invocar directamente count_loop ();devolver 0 ; }

El código con bloques debe compilarse con -fblocksy enlazarse con-lBlocksRuntime

C++

C++ (desde C++11 ) admite funciones anónimas (técnicamente objetos de función ), llamadas expresiones lambda , [ 3 ] que tienen la forma: donde " " tiene la forma " en ese orden; cada uno de estos componentes es opcional". Si está ausente, el tipo de retorno se deduce de las instrucciones como si fuera para una función con un tipo de retorno declarado .[captures]<template-parameters>(params) specsrequires (...) -> returns { body }specsspecifiersexceptionattributes -> trailing-return-typereturnauto

A partir de C++20 , los parámetros de plantilla también se pueden declarar explícitamente en el área.<template-parameters>

Este es un ejemplo de expresión lambda, con un atributo :[[nodiscard]]

auto f = []( int x , int y ) [[ nodiscard ]] -> int { return x + y ; };

C++ también admite cierres , aquí llamados capturas. Las capturas se definen entre corchetes [y ]en la declaración de la expresión lambda. Este mecanismo permite capturar estas variables por valor o por referencia. La siguiente tabla lo demuestra:

// Sin capturas, la lambda es implícitamente convertible a un puntero a función. auto a = [] -> void {}; // x se captura por valor e y se captura por referencia. auto b = [ x , & y ] -> void {}; // Cualquier variable externa se captura implícitamente por referencia si se usa. auto c = [ & ] -> void {}; // Cualquier variable externa se captura implícitamente por valor si se usa. auto d = [ = ] -> void {}; // x se captura por valor. Otras variables se capturarán por referencia. auto e = [ & , x ] -> void {}; // z se captura por referencia. Otras variables se capturarán por valor. auto f = [ = , & z ] -> void {};

Las variables capturadas por valor son constantes por defecto. Si se añaden mutabledespués de la lista de parámetros, dejan de ser constantes.

C++14 y versiones posteriores admiten init-capture, por ejemplo:

usando std :: unique_ptr ;unique_ptr < int > ptr = std :: make_unique < int > ( 42 );// La asignación de copia se elimina para un puntero único auto a = [ ptr ] -> void { // ... };// OK auto b = [ ptr = std :: move ( ptr )] -> void { // ... };// Se requiere mutable para modificar 'i' auto counter = [ i = 0 ]() mutable -> int { return i ++ ; };contador (); // 0 contador (); // 1 contador (); // 2

Los dos ejemplos siguientes demuestran el uso de una expresión lambda:

usando std :: vector ;vector < int > someList { 1 , 2 , 3 , 4 , 5 }; int total = 0 ; std :: ranges :: for_each ( someList , [ & total ]( int x ) -> void { total += x ; } ); // Tenga en cuenta que std::ranges::fold_left es una alternativa preferible aquí

Esto calcula el total de todos los elementos de la lista. La variable totalse almacena como parte del cierre de la función lambda. Dado que es una referencia a la variable de pila total, puede cambiar su valor.

usando std :: vector ;vector < int > someList { 1 , 2 , 3 , 4 , 5 }; int total = 0 ; int value = 5 ; std :: ranges :: for_each ( someList , [ & total , value , this ]( int x ) -> void { total += x * value * this -> someFunc (); } );

Esto hará totalque se almacene como referencia, pero valuese almacenará como una copia.

La captura de thises especial. Solo se puede capturar por valor, no por referencia. Sin embargo, en C++17 , el objeto actual se puede capturar por valor (denotado por *this), o se puede capturar por referencia (denotado por this). thissolo se puede capturar si la función contenedora más cercana es una función miembro no estática. La expresión lambda tendrá el mismo acceso que el miembro que la creó, en términos de miembros protegidos/privados.

Si thisse captura, ya sea explícita o implícitamente, también se comprueba el alcance de los miembros de la clase incluidos. El acceso a los miembros thisno requiere el uso explícito de this->sintaxis.

La implementación interna específica puede variar, pero se espera que una función lambda que captura todo por referencia almacene el puntero de pila real de la función en la que se crea, en lugar de referencias individuales a variables de pila. Sin embargo, dado que la mayoría de las funciones lambda son pequeñas y de ámbito local, son candidatas ideales para la optimización en línea y, por lo tanto, no necesitan almacenamiento adicional para referencias.

Si se invoca un objeto de cierre que contiene referencias a variables locales después del ámbito de 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, por lo que las lambdas pueden verse como tipos generados por el compilador que implementan una operator(). Debido a que el tipo de una lambda está especificado por el compilador, generalmente se almacena en autopara la deducción de tipos . Las lambdas también pueden almacenarse en , pero esto usa borrado de tipo , mientras que almacenar en un puntero de función no permite capturas en la lambda. Si el usuario desea tomar una función lambda como parámetro, el tipo de parámetro debe ser un tipo de plantilla, o debe crear un o un objeto similar para capturar el valor de la lambda. El uso de la palabra clave puede ayudar a almacenar la función lambda,std::function<R(Ts...)>std::functionauto

auto myLambdaFunc = [ & ]( int x ) -> void { // ... };auto myHeapLambdaFunc = new auto ([ = ]( int x ) -> void { // ... });

Aquí hay un ejemplo de cómo almacenar funciones anónimas en variables, vectores y matrices, y cómo pasarlas como parámetros con nombre:

importar std ;usando std :: function ; usando std :: vector ;double eval ( function < double ( double ) > f , double x = 2.0 ) { return f ( x ); }int main ( int argc , char * argv []) { function < double ( double ) > f0 = []( double x ) -> double { return 1.0f ; };auto f1 = []( double x ) -> double { return x ; };decltype ( f0 ) fa [ 3 ] = { f0 , f1 , []( double x ) -> double { return x * x ; }};vector < decltype ( f0 ) > fv = { f0 , f1 }; fv . push_back ([]( double x ) -> double { return x * x ; });for ( size_t i = 0 ; i < fv . size (); ++ i ) { std :: println ( "{}" , fv [ i ]( 2.0 )); }for ( size_t i = 0 ; i < 3 ; ++ i ) { std :: println ( "{}" , fa [ i ]( 2.0 )); }for ( decltype ( f0 ) & f : fv ) { std :: println ( "{}" , f ( 2.0 )); }for ( decltype ( f0 ) & f : fa ) { std :: println ( "{}" , f ( 2.0 )); }std :: println ( "{}" , f ( 2.0 )); std :: println ( "{}" , eval ( f0 )); std :: println ( "{}" , eval ( f1 )); std :: println ( "{}" , eval ([]( double x ) -> double { return x * x ; })); }

Una expresión lambda con una especificación de captura vacía ( []) puede convertirse implícitamente en un puntero a función del mismo tipo con el que se declaró la lambda. Por lo tanto, esto es válido:

auto aLambdaFunc = []( int x ) -> void { // ... }; void ( * funcPtr )( int ) = aLambdaFunc ; funcPtr ( 4 ); // llama a la lambda.

Desde C++14 , los parámetros de función de una expresión lambda se pueden declarar con auto. La expresión lambda resultante se denomina expresión lambda genérica y es esencialmente una plantilla de función anónima, ya que las reglas para la deducción de tipos de los parámetros auto son las mismas que las de la deducción de argumentos de plantilla.

Desde C++17 , una lambda puede declararse como constexpr, y desde C++20 , constevalcon la semántica habitual. Estos especificadores van después de la lista de parámetros, como mutable. A partir de C++23 , la lambda también puede ser staticsi no tiene capturas. Los especificadores staticy mutableno se pueden combinar.

Desde C++23, una expresión lambda puede ser recursiva a través de un parámetro explícito thiscomo primer parámetro:

auto fibonacci = []( this auto self , int n ) -> void { return n <= 1 ? n : self ( n - 1 ) + self ( n - 2 ); }; fibonacci ( 7 ); // 13

Además, C++23 modificó la sintaxis para que se puedan omitir los paréntesis en el caso de una expresión lambda que no recibe argumentos, incluso si tiene un especificador. También estableció que una secuencia de especificadores de atributos que aparece antes de la lista de parámetros, los especificadores de lambda o el especificador noexcept (debe haber uno de ellos) se aplica al operador de llamada a función o a la plantilla de operador del tipo de cierre. De lo contrario, se aplica al tipo del operador de llamada a función o de la plantilla de operador. Anteriormente, dicha secuencia siempre se aplicaba al tipo del operador de llamada a función o de la plantilla de operador del tipo de cierre, lo que hacía, por ejemplo, imposible usar el atributo con expresiones lambda.[[noreturn]]

DO#

En C# , la compatibilidad con funciones anónimas se ha profundizado a través de las distintas versiones del compilador del lenguaje. La versión 3.0 del lenguaje, lanzada en noviembre de 2007 con .NET Framework v3.5, ofrece compatibilidad total con funciones anónimas. [ 4 ] : 7–8 [ 5 ] : 26 C# las denomina expresiones lambda , siguiendo la versión original de las funciones anónimas, el cálculo lambda . [ 6 ] [ 4 ] : 7–8, 91 [ 5 ] : 91

usando el sistema ;// el primer int es el tipo x' // el segundo int es el tipo de retorno // <see href="http://msdn.microsoft.com/en-us/library/bb549151.aspx" /> Func < int , int > foo = x => x * x ; Console . WriteLine ( foo ( 7 ));

Aunque la función es anónima, no se puede asignar a una variable de tipo implícito, porque la sintaxis lambda puede usarse para denotar una función anónima o un árbol de expresiones, y el compilador no puede decidir automáticamente la elección. [ 4 ] : 101–103 Por ejemplo, esto no funciona:

usando el sistema ;// ¡NO compilará! Func < int , int > foo = ( int x ) => x * x ;

Sin embargo, una expresión lambda puede participar en la inferencia de tipos y puede usarse como argumento de un método , por ejemplo, para usar funciones anónimas con la capacidad Map disponible con System.Collections.Generic.List(en el ConvertAll()método):

usando System.Collections.Generic ;// Inicializar la lista: List < int > values ​​= new ( 7 , 13 , 4 , 9 , 3 ); // Aplicar la función anónima a todos los elementos de la lista y devolver la nueva lista List < int > foo = values ​​. ConvertAll ( d => d * d ); // El resultado de la variable foo es de 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 con .NET Framework v1.0, proporcionó soporte parcial para funciones anónimas mediante el uso de delegados . [ 4 ] : 6 C# los denomina expresiones lambda , siguiendo la versión original de funciones anónimas, el cálculo lambda . [ 4 ] : 91 Esta construcción es algo similar a los delegados de PHP. En C# 1.0, los delegados son como punteros a funciones que se refieren a un método con nombre explícito dentro de una clase. (Pero a diferencia de PHP, el nombre no es necesario en el momento en que se usa el delegado). C# v2.0, lanzado en noviembre de 2005 con .NET Framework v2.0, introdujo el concepto de métodos anónimos como una forma de escribir bloques de instrucciones en línea sin nombre que se pueden ejecutar en una invocación de delegado. [ 4 ] : 6–7 C# 3.0 continúa admitiendo estas construcciones, pero también admite la construcción de expresiones lambda.

Este ejemplo se compilará en C# 3.0 y muestra las tres formas:

espacio de nombres Wikipedia.Ejemplos ;usando el sistema ;public class TestDriver { delegate int SquareDelegate ( int d ); static int Square ( int d ) { return d * d ; } static void Main ( string [] args ) { // C# 1.0: Se necesita la sintaxis original del delegado // inicialización con un método con nombre. SquareDelegate A = new ( Square ); Console . WriteLine ( A ( 3 )); // C# 2.0: Un delegado se puede inicializar con // código en línea, llamado "método anónimo". Este // método toma un int como parámetro de entrada. SquareDelegate B = delegate ( int d ) { return d * d ; }; Console . WriteLine ( B ( 5 )); // C# 3.0. Un delegado se puede inicializar con // una expresión lambda. La lambda toma un int y devuelve un int. // El tipo de x es inferido por el compilador. SquareDelegate C = x => x * x ; Console . 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 ; Console.WriteLine ( D ( 9 ) ) ; } }

En el caso de la versión C# 2.0, el compilador de 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 obtiene un nombre generado, por supuesto; este nombre generado se basa en el nombre del método en el que se declara el Delegado. Pero el nombre no se expone al código de la aplicación excepto mediante reflexión . [ 4 ] : 103 En el caso de la versión C# 3.0, se aplica el mismo mecanismo.

Lenguaje de marcado ColdFusion (CFML)

Utilizando elfunciónpalabra clave:

fn = función (){ // instrucciones };

O utilizando una función flecha:

fn = () => { // instrucciones };fn = () => singleExpression // singleExpression se devuelve implícitamente. No es necesario usar las llaves ni la palabra clave return.fn = singleParam => { // si la función flecha tiene solo un parámetro, no es necesario usar paréntesis // instrucciones }fn = ( x , y ) => { // si la función flecha tiene cero o varios parámetros, es necesario usar paréntesis // instrucciones }

CFML admite cualquier instrucción dentro de la definición de la función, no solo expresiones.

CFML admite funciones anónimas recursivas:

factorial = función ( n ){ return n > 1 ? n * factorial ( n - 1 ) : 1 ; };

Las funciones anónimas de CFML implementan el cierre.

D

D utiliza delegados en línea para implementar funciones anónimas. La sintaxis completa para un delegado en línea es

ReturnType delegate ( Args args ) { // cuerpo }

Si no hay ambigüedad, se pueden 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 ; } // lo mismo delegate double ( int x ) { return x * x ; } // si el tipo de retorno debe forzarse manualmente

Desde la versión 2.0, D asigna cierres en el montón a menos que el compilador pueda demostrar que no es necesario; la scopepalabra clave se puede usar para forzar la asignación en la pila. Desde la versión 2.058, es posible usar la notación abreviada:

x => x * x ; ( int x ) => x * x ; ( x , y ) => x * y ; ( int x , int y ) => x * y ;

Se puede asignar una función anónima a una variable y usarla de esta manera:

auto sqr = ( double x ) { return x * x ; }; double y = sqr ( 4 );

Dardo

Dart admite funciones anónimas. [ 7 ]

var sqr = ( x ) => x * x ; print ( sqr ( 5 ));

o

imprimir ((( x ) => x * x )( 5 ));

Delfos

Delphi introdujo las funciones anónimas en la versión 2009.

demostración del programa ;tipo TSimpleProcedure = referencia al procedimiento ; TSimpleFunction = referencia a la función ( const x : cadena ) : entero ;var x1 : TProcedimientoSimple ; y1 : TFunciónSimple ;begin x1 := procedure begin Writeln ( 'Hola Mundo' ) ; end ; x1 ; //invocar el método anónimo recién definidoy1 := function ( const x : string ) : Integer begin Result := Length ( x ) ; end ; Writeln ( y1 ( 'bar' )) ; end .

PascalABC.NET

PascalABC.NET admite funciones anónimas mediante sintaxis lambda.

begin var n := 10000000 ; var pp := ( 1 .. n ) . Select ( x -> ( Random , Random )) . Where ( p -> Sqr ( p [ 0 ]) + Sqr ( p [ 1 ]) < 1 ) . Count / n * 4 ; Print ( pp ) ; end .

Elixir

Elixir utiliza el cierrefn para funciones anónimas. [ 8 ]

iex> suma = fn ( a , b ) -> a + b end iex> suma . ( 4 , 3 ) 7 iex> cuadrado = fn ( x ) -> x * x end iex> Enum . map [ 1 , 2 , 3 , 4 ], cuadrado [1, 4, 9, 16]

Erlang

Erlang utiliza una sintaxis para funciones anónimas similar a la de las funciones con nombre. [ 9 ]

% Función anónima vinculada a la variable Square Square = fun ( X ) -> X * X end .% Función nombrada con la misma funcionalidad cuadrado ( X ) -> X * X .

Ir

Go admite funciones anónimas. [ 10 ]

foo := func ( x int ) int { return x * x } fmt . Println ( foo ( 10 ))

Haskell

Haskell utiliza una sintaxis concisa para las funciones anónimas (expresiones lambda). Se supone que la barra invertida se asemeja a λ.

\ x -> x * x

Las expresiones lambda están totalmente integradas con el motor de inferencia de tipos y admiten toda la sintaxis y las características de las funciones "ordinarias" (excepto el uso de múltiples definiciones para la coincidencia de patrones, ya que la lista de argumentos solo se especifica una vez).

map ( \ x -> x * x ) [ 1 .. 5 ] -- devuelve [1, 4, 9, 16, 25]

Los siguientes son todos equivalentes:

f x y = x + y f x = \ y -> x + y f = \ x y -> x + y

Haxe

En Haxe , las funciones anónimas se llaman lambda y utilizan la sintaxis function(argument-list) expression;.

var f = function ( x ) return x * x ; f ( 8 ); // 64( función ( x , y ) devuelve x + y )( 5 , 6 ); // 11

Java

Java admite funciones anónimas, llamadas expresiones Lambda , a partir de JDK 8. [ 11 ]

Una expresión lambda consta de una lista de parámetros formales separados por comas y encerrados entre paréntesis, un token 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 constar de una instrucción o un bloque de instrucciones. [ 12 ]

import java.util.Optional ; import java.util.function.BiFunction ; import java.util.function.BinaryOperator ; import java.util.function.Function ;// Sin parámetros Runnable r = () -> System . out . println ( "Hola, mundo!" );// Con un parámetro (este ejemplo es una función identidad). Función < Objeto , Objeto > identidad = a -> a ;// Con una expresión BinaryOperator < Integer > add = ( a , b ) -> a + b ;// Con información de tipo explícita y un bloque de código BiFunction < Long , String , String > formatter = ( long id , String name ) -> { String . format ( "id: %f, name: %s" , id , name ); }// Con múltiples declaraciones en el cuerpo de la lambda. Necesita un bloque de código. // Este ejemplo también incluye dos expresiones lambda anidadas (la primera también es un cierre). BiFunction < Long , Double , Double > getPriceOrDefault = ( double id , double defaultPrice ) -> { Optional < Product > product = productList . stream () . filter ( p -> p . getId () == id ) . findFirst ();return producto . map ( Producto :: obtenerPrecio ()) . orElse ( precio predeterminado ); }

Las expresiones lambda no pueden especificar throwscláusulas. Las expresiones lambda en sí mismas no son expresiones completas de tipos concretos, sino más bien expresiones polimórficas, cuyo tipo está influenciado por el tipo de destino circundante en lugar de estarlo completamente por su propio contenido.

import java.util.function.Function ;// Inválido, ya que las expresiones lambda en sí mismas no tienen un tipo independiente var f = ( int x ) -> x + 1 ; // En su lugar debería ser: Function < Integer , Integer > f = x -> x + 1 ;

Las expresiones lambda implementan alguna interfaz funcional de destino (como java.lang.Runnable, etc.), que es cualquier interfaz que define solo un método (excluyendo aquellas que se heredan de java.lang.Object); adicionalmente se puede anotar con @FunctionalInterfacepara que el compilador imponga que una interfaz es realmente una interfaz funcional. [ 13 ] [ 12 ]

clase pública Calculadora { interfaz MatemáticasEntero { int operación ( 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 . printf ( "40 + 2 = %d%n" , apply ( 40 , 2 , addition )); System . out . printf ( "20 - 10 = %d%n" , apply ( 20 , 10 , subtraction )); System . out . printf ( "10 - 20 = %d%n" , apply ( 20 , 10 , subtraction . swap ())); } }

En este ejemplo, se declara una interfaz funcional llamada IntegerMath. Las expresiones lambda que implementan IntegerMathse pasan al apply()método que se va a ejecutar. Los métodos predeterminados como swapdefinen métodos en funciones.

Java 8 introdujo otro mecanismo llamado 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 ni el tipo de argumentos, ya que estos se extraen del método abstracto de la interfaz funcional.

IntBinaryOperator suma = Entero :: suma ;

En el ejemplo anterior, la interfaz funcional IntBinaryOperatordeclara 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.

Diferencias en comparación con las clases anónimas

Las clases anónimas de interfaces compatibles con lambda son similares, pero no exactamente equivalentes, a las expresiones lambda. Para ilustrarlo, en el siguiente ejemplo, anonymousClassy lambdaExpressionson ambas instancias de IntegerMathque suman sus dos parámetros:

IntegerMath anonymousClass = new IntegerMath () { @Override public int operation ( int a , int b ) { return a + b ; } };IntegerMath lambdaExpression = ( a , b ) -> a + b ;

La principal diferencia aquí es que la expresión lambda no necesita necesariamente asignar una nueva instancia para el IntegerMath, y puede devolver la misma instancia cada vez que se ejecuta este código. [ 14 ] Además, al menos en la implementación de OpenJDK , las lambdas se compilan para invocar instrucciones dinámicas, con el cuerpo de la lambda insertado como un método estático en la clase circundante, [ 15 ] en lugar de generar un nuevo archivo de clase por completo.

Si una lambda implementa una interfaz funcional que extiende java.lang.Serializable, entonces cuando la lambda se serializa, se convierte en un java.lang.invoke.SerializedLambda[ 16 ] , que captura información sobre la lambda misma, llamada su "forma serializada". [ 17 ] Esto es necesario, porque las clases de implementación de lambda son sintéticas y específicas de la JVM, y por lo tanto deben reconstruirse exactamente en otra invocación de la JVM. Al igual que en C++, los nombres de los tipos de lambda son sintéticos y generados por el compilador con detalles de implementación no especificados.

Runnable r = () -> System . out . println ( "Hola" );// Podría imprimir algo como: // class org.wikipedia.examples.Main$$Lambda$1/0x0000000800b00440 System . out . println ( r . getClass ());

Las expresiones lambda no generan archivos de clase , sino que emiten una invokedynamicinstrucción en la JVM, que el entorno de ejecución utiliza para crear una clase de implementación adecuada.

Las expresiones lambda de captura suelen ser objetos distintos, debido a que requieren un estado capturado almacenado; sin embargo, las expresiones lambda que no son de captura pueden ser potencialmente singletons .

Runnable r1 = () -> {}; Runnable r2 = () -> {};System.out.println ( r1 == r2 ) ; // Puede imprimir verdadero o falso; lo determina la JVM

Sin embargo, a diferencia de C++, los tipos lambda no forman parte del modelo de lenguaje ; no se puede depender de nada de su clase de tiempo de ejecución, mientras que en C++ el tipo lambda aún se puede extraer decltypepara obtener un tipo de cierre único real; el de una lambda java.lang.Class<?>no se puede referenciar en el código.

Limitaciones de Java

Las expresiones lambda de Java 8 tienen las siguientes limitaciones:

  • Las funciones Lambda pueden generar excepciones controladas, pero dichas funciones Lambda no funcionarán con las interfaces utilizadas por la API de colecciones.
  • Las variables que se encuentran dentro del ámbito donde se declara la expresión lambda solo pueden ser accedidas dentro de la expresión lambda si son efectivamente finales, es decir, si la variable no se modifica dentro o fuera del ámbito de la expresión lambda.

JavaScript

JavaScript / ECMAScript admite funciones anónimas.

alerta (( función ( x ) { devolver x * x ; })( 10 ));

ES6 admite la sintaxis de "función flecha", donde un símbolo => separa la lista de parámetros de la función anónima del cuerpo:

alerta (( x => x * x )( 10 ));

Esta estructura se usa a menudo en los 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.

documento.título = ubicación.href ;

Sin embargo, dado que la instrucción de asignación devuelve un valor (la propia URL), muchos navegadores crean una nueva página para mostrar dicho valor.

En su lugar, se puede utilizar una función anónima que no devuelva ningún valor:

( función () { documento . título = ubicación . href ; })();

La instrucción de función en el primer par de paréntesis (exterior) declara una función anónima, que luego se ejecuta cuando se usa con el último par de paréntesis. Esto es casi equivalente a lo siguiente, que rellena el entorno con, fa diferencia de una función anónima.

var f = function () { document . title = location . href ; }; f ();

Utilice void() para evitar nuevas páginas para funciones anónimas arbitrarias:

void ( function () { return document . title = location . href ; }());

o simplemente:

void ( document.title = location.href ) ;

JavaScript presenta sutilezas sintácticas en la semántica de la definición, invocación y evaluación de funciones anónimas. Estos matices implícitos son consecuencia directa de la evaluación de expresiones entre paréntesis. Las siguientes construcciones, denominadas expresiones de función invocadas inmediatamente, ilustran este concepto:

( función () { /* ... */ }())

y

( función () { /* ... */ })()

Representando " function () { /* ... */ }" por f, la forma de las construcciones son un paréntesis dentro de un paréntesis (f())y un paréntesis aplicado a un paréntesis (f)().

Nótese la ambigüedad sintáctica general de una expresión entre paréntesis, los argumentos entre paréntesis de una función y los paréntesis que rodean los parámetros formales en la definición de una función. En particular, JavaScript define un ,operador (coma) 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 sintaxis de los parámetros formales de la función)! Si fno se identifica en las construcciones anteriores, se convierten en (())y ()(). La primera no proporciona ninguna pista sintáctica de ninguna función residente, pero la segunda DEBE evaluar la primera expresión entre paréntesis como una función para ser JavaScript válido. (Nota: por ejemplo, los ()' podrían 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 igual manera, los objetos son instancias de función) y los corchetes de notación literal de objeto, {}para el código entre llaves, se utilizan al definir una función de esta manera (a diferencia de usar new Function(...)). En un sentido muy amplio y no riguroso (especialmente porque las vinculaciones globales están comprometidas), una secuencia arbitraria de instrucciones JavaScript entre llaves, {stuff}, puede considerarse un punto fijo de

( función () { ( función () { ( ... {( función () { /* cosas */ }() )} ... ) }() ) }() )

Más correctamente, pero con salvedades,

( función () { /* cosas */ }() ) ~= fixedPointOf ( función () { return función () { return ... { return función () { /* cosas */ }() } ... }() }())

Observe las implicaciones de la función anónima en los fragmentos de JavaScript que siguen:

  • function () { /* ... */ }()sin rodear ()'s generalmente no es legal
  • (f = function () { /* ... */ })no "olvida" fglobalmente a diferencia de(function f () { /* ... */ })
Las métricas de rendimiento para analizar la complejidad espacial y temporal de las llamadas a funciones, la pila de llamadas , etc., en un motor intérprete de JavaScript se implementan fácilmente con estas últimas construcciones de funciones anónimas. A partir de las implicaciones de los resultados, es posible deducir algunos detalles de la implementación recursiva frente a la iterativa de un motor, especialmente la recursión de cola .

Julia

En Julia, las funciones anónimas se definen utilizando la sintaxis (arguments)->(expression),

julia> f = x- > x * x ; f ( 8 ) 64 julia> (( x , y ) -> x + y )( 5 , 6 ) 11

Kotlin

Kotlin admite funciones anónimas con la sintaxis {arguments -> expression},

val sum = { x : Int , y : Int -> x + y } sum ( 5 , 6 ) // devuelve 11 val even = { x : Int -> x % 2 == 0 } even ( 4 ) // devuelve true

Ceceo

Lisp y Scheme admiten funciones anónimas mediante la construcción "lambda", que hace referencia al cálculo lambda . Clojure admite funciones anónimas con la forma especial "fn" y la sintaxis de lectura #().

( lambda ( arg ) ( * arg arg ))

Lisp común

Common Lisp utiliza el concepto de expresiones lambda. Una expresión lambda se escribe como una lista cuyo primer elemento es el símbolo "lambda". Esta lista contiene los argumentos, la documentación o las declaraciones y el cuerpo de la función. Las expresiones lambda se pueden usar dentro de formas lambda y con el operador especial "function".

( función ( lambda ( arg ) ( hacer algo arg )))

"Función" se puede abreviar como #'. Además, existe la macro lambda , que se expande en una forma de función:

; usando comillas marcadas #' ( lambda ( arg ) ( hacer algo arg )) ; usando la macro lambda: ( lambda ( arg ) ( hacer algo arg ))

Un uso típico de las 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 con los resultados.

( mapcar #' ( lambda ( x ) ( * x x )) ' ( 1 2 3 4 )) ; -> (1 4 9 16)

La forma lambda en Common Lisp permite escribir una expresión lambda en una llamada a una función:

(( lambda ( x y ) ( + ( sqrt x ) ( sqrt y ))) 10.0 12.0 )

Las funciones anónimas en Common Lisp también pueden recibir nombres globales posteriormente:

( setf ( symbol-function 'sqr ) ( lambda ( x ) ( * x x ))) ; lo que nos permite llamarlo usando el nombre SQR: ( sqr 10.0 )

Esquema

Las funciones con nombre de Scheme son simplemente azúcar sintáctico para funciones anónimas vinculadas a nombres:

( define ( somename arg ) ( do-something arg ))

se expande (y es equivalente) a

( define algúnnombre ( lambda ( arg ) ( hacer algo arg )))

Clojure

Clojure admite funciones anónimas a través de la forma especial "fn":

( fn [ x ] ( + x 3 ))

También existe una sintaxis de lector para definir una expresión lambda:

# ( + % %2%3 ) ; Define una función anónima que toma tres argumentos y los suma.

Al igual que Scheme, las "funciones con nombre" de Clojure son simplemente azúcar sintáctico para las expresiones lambda vinculadas a nombres:

( definición de función [ arg ] ( + 3arg ) )

se expande a:

( def func ( fn [ arg ] ( + 3 arg )))

Lua

En Lua (al igual que en Scheme), todas las funciones son anónimas. Una función con nombre en Lua es simplemente una variable que contiene una referencia a un objeto función. [ 18 ]

Así, en Lua

función foo ( x ) devuelve 2 * x fin

es simplemente azúcar sintáctico para

foo = función ( x ) devuelve 2 * x fin

Un ejemplo de cómo usar funciones anónimas para ordenar en orden inverso:

tabla.ordenar ( red , función ( a , b ) devolver a . nombre > b . nombre fin )

Lenguaje Wolfram, Mathematica

Wolfram Language es el lenguaje de programación de Mathematica . Las funciones anónimas son importantes en la programación de este último. Existen varias formas de crearlas. A continuación se muestran algunas funciones anónimas que incrementan un número. La primera es la más común. #1Se refiere al primer argumento y &marca el final de la función anónima.

#1 + 1 & Función [ x , x + 1 ] x \ [ Función ] x + 1

Por ejemplo:

f := #1 ^ 2 & ; f [ 8 ] 64 #1 + #2 & [ 5 , 6 ] 11

Además, Mathematica cuenta con una construcción adicional para crear funciones anónimas recursivas. El símbolo '#0' se refiere a la función completa . La siguiente función calcula el factorial de su entrada:

Si [ #1 == 1 , 1 , #1 * #0 [ #1 -1 ]] &

Por ejemplo, el factorial de 6 sería:

Si [ #1 == 1 , 1 , #1 * #0 [ #1 -1 ]] & [ 6 ] 720

MATLAB, Octave

Las funciones anónimas en MATLAB u Octave se definen utilizando la sintaxis @(argument-list)expression. Cualquier variable que no se encuentre en la lista de argumentos se hereda del ámbito que la contiene y se captura por valor.

>> f = @( x ) x * x ; f ( 8 ) ans = 64 >> (@( x , y ) x + y )( 5 , 6 ) % Solo funciona en Octave ans = 11

Máxima

En Maxima, las funciones anónimas se definen utilizando la sintaxis lambda(argument-list,expression),

f : lambda ([ x ], x * x ); f ( 8 ); 64lambda ([ x , y ], x + y )( 5 , 6 ); 11

ML

Los distintos dialectos de ML admiten funciones anónimas.

En OCaml, las funciones anónimas son funciones sin nombre declarado. Aquí hay un ejemplo de una función anónima que multiplica su entrada por dos:

diversión x -> x * 2

En el ejemplo, `fun` es una palabra clave que indica que la función es anónima. Pasamos un argumento `x` y `->` para separar el argumento del cuerpo. [ 19 ]

F#

F# admite funciones anónimas, [ 20 ] de la siguiente manera:

( fun x -> x * x ) 20 // 400

ML estándar

Standard ML admite funciones anónimas, como se indica a continuación:

fn arg => arg * arg

Nim

Nim admite funciones anónimas de múltiples líneas y múltiples expresiones. [ 21 ]

var anon = proc ( var1 , var2 : int ): int = var1 + var2 assert anon ( 1 , 2 ) == 3

Ejemplo de varias líneas:

var anon = func ( x : int ): bool = if x > 0 : result = true else : result = falseafirmar anónimo ( 9 )

Las funciones anónimas pueden pasarse como parámetros de entrada de otras funciones:

var ciudades = @[ "Frankfurt" , "Tokio" , "Nueva York" ]ciudades.ordenar ( proc ( x , y : cadena ) : int = cmp ( x.len , y.len ) )

Una función anónima es básicamente una función sin nombre.

Perl

Perl 5

Perl 5 admite funciones anónimas, [ 22 ] de la siguiente manera:

( sub { print "Me llamaron\n" }) -> (); # 1. completamente anónimo, llamado como se creómy$squarer=sub{my$x=shift;$x*$x};# 2. assigned to a variablesubcurry{my($sub,@args)=@_;returnsub{$sub->(@args,@_)};# 3. as a return value of another function}# example of currying in Perl programmingsubsum{my$tot=0;$tot+=$_for@_;$tot}# returns the sum of its argumentsmy$curried=curry\&sum,5,7,9;print$curried->(1,2,3),"\n";# prints 27 ( = 5 + 7 + 9 + 1 + 2 + 3 )

Other constructs take bare blocks as arguments, which serve a function similar to lambda functions of one parameter, but do not have the same parameter-passing convention as functions -- @_ is not set.

my@squares=map{$_*$_}1..10;# map and grep don't use the 'sub' keywordmy@square2=map$_*$_,1..10;# braces unneeded for one expressionmy@bad_example=map{printfor@_}1..10;# values not passed like normal Perl function

PHP

Before 4.0.1, PHP had no anonymous function support.[23]

PHP 4.0.1 to 5.3

PHP 4.0.1 introduced the create_function which was the initial anonymous function support. This function call makes a new randomly named function and returns its name (as a string)

$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 la función deben ir entre comillas simples, o bien, los signos de dólar deben escaparse. De lo contrario, PHP asume que " $x" se refiere a la variable $xy la sustituirá en la cadena (aunque posiblemente no exista) en lugar de dejar " $x" en la cadena. Para funciones con comillas o con muchas variables, puede resultar bastante tedioso asegurarse de que el cuerpo de la función previsto sea el que PHP interpreta.

Cada invocación create_functioncrea una nueva función, que permanece activa durante el resto del programa y no puede ser liberada por el recolector de basura , consumiendo memoria del programa de forma irreversible. Si esto se utiliza para crear funciones anónimas repetidamente, por ejemplo, dentro de un bucle, puede causar problemas como un consumo excesivo de memoria.

PHP 5.3

PHP 5.3 agregó una nueva clase llamada Closurey un método mágico __invoke()que hace que una instancia de clase sea invocable. [ 24 ]

$x = 3 ; $func = function ( $z ) { return $z * 2 ; }; echo $func ( $x ); // imprime 6

En este ejemplo, $funces una instancia de Closurey echo $func($x)es equivalente a echo $func->__invoke($x). PHP 5.3 imita las funciones anónimas, pero no admite funciones verdaderamente anónimas porque las funciones de PHP todavía no son objetos de primera clase.

PHP 5.3 sí admite cierres, pero las variables deben indicarse explícitamente como tales:

$x = 3 ; $func = function () use ( & $x ) { $x *= 2 ; }; $func (); echo $x ; // imprime 6

La variable $xestá vinculada por referencia, por lo que la invocación de $funcla función la modifica y los cambios son visibles fuera de la función.

PHP 7.4

Las funciones flecha se introdujeron en PHP 7.4.

$x = 3 ; $func = fn ( $z ) => $z * 2 ; echo $func ( $x ); // imprime 6

Los dialectos de Prolog

Logtalk

Logtalk utiliza la siguiente sintaxis para predicados anónimos (expresiones lambda):

{ FreeVar1 , FreeVar2 , ... } / [ LambdaParameter1 , LambdaParameter2 , ...] >> Objetivo

Un ejemplo sencillo sin variables libres y utilizando un predicado de mapeo de lista es:

| ?- meta :: map([ X , Y ] >> ( Y es 2 * X ), [ 1 , 2 , 3 ], Ys ). Ys = [ 2 , 4 , 6 ] Sí 

También se admite el currying. El ejemplo anterior se puede escribir como:

| ?- meta :: map([ X ] >> ([ Y ] >> ( Y es 2 * X )), [ 1 , 2 , 3 ], Ys ). Ys = [ 2 , 4 , 6 ] Sí 

Prólogo visual

Las funciones anónimas (en general, los predicados anónimos ) se introdujeron en Visual Prolog en la versión 7.2. [ 25 ] Los predicados anónimos pueden capturar valores del contexto. Si se crean en un miembro de objeto, también pueden acceder al estado del objeto (capturando This).

mkAdderDevuelve una función anónima que ha capturado el argumento Xen el cierre. La función devuelta es una función que agrega Xa su argumento:

cláusulas mkAdder ( X ) = { ( Y ) = X + Y }.

Pitón

Python admite funciones anónimas simples mediante la forma lambda. [ 26 ] El cuerpo ejecutable de la lambda debe ser una expresión y no puede ser una instrucción, lo cual es una restricción que limita su utilidad. El valor devuelto por la lambda es el valor de la expresión contenida. Las formas lambda se pueden usar donde se pueden usar funciones ordinarias. Sin embargo, estas restricciones la convierten en una versión muy limitada de una función normal. Aquí hay un ejemplo:

from typing import Callablefoo : Callable [[ int ], int ] = lambda x : x * x print ( foo ( 10 )) # imprime 100

En general, la convención de Python fomenta el uso de funciones con nombre definidas en el mismo ámbito en el que normalmente se usaría una función anónima en otros lenguajes. Esto es aceptable, ya que las funciones definidas localmente implementan toda la potencia de los cierres y son casi tan eficientes como el uso de una expresión lambda en Python. En este ejemplo, se puede decir que la función integrada `power` ha sido currificada :

def make_pow ( n : int ) -> Callable [[ int ], int ]: def fixed_exponent_pow ( x : int ) -> int : return pow ( x , n ) return fixed_exponent_powcuadrado : Callable [[ int ], int ] = make_pow ( 2 ) print ( cuadrado ( 10 )) # imprime 100 cubo : Callable [[ int ], int ] = make_pow ( 3 ) print ( cubo ( 10 )) # imprime 1000

R

En R, las funciones anónimas se definen utilizando la sintaxis function(argument-list)expression, que tiene una forma abreviada desde la versión 4.1.0 \, similar a Haskell.

> f <- function ( x ) x * x ; f ( 8 ) [1] 64 > ( function ( x , y ) x + y )( 5 , 6 ) [1] 11 > # Desde R 4.1.0 > ( \ ( x , y ) x + y )( 5 , 6 ) [1] 11

Raku

En Raku , todos los bloques (incluso los asociados con if, while, etc.) son funciones anónimas. Un bloque que no se utiliza como rvalue se ejecuta inmediatamente.

  1. totalmente anónimo, llamado como creado
    { decir "Me llamaron" }; 
  2. asignado a una variable
    mi $squarer1 = -> $x { $x * $x }; # 2a. bloque puntiagudo mi $squarer2 = { $^x * $^x }; # 2b. twigil mi $squarer3 = { mi $x = shift @_ ; $x * $x }; # 2c. estilo Perl 5
  3. zurra
    sub add ( $m , $n ) { $m + $n } my $seven = add ( 3 , 4 ); my $add_one = &add . assume ( m => 1); my $eight = $add_one ( $seven ); 
  4. Objeto WhateverCode
    mi $w = * - 1 ; # Objeto WhateverCode mi $b = { $_ - 1 }; # misma funcionalidad, pero como bloque Callable

Rubí

Ruby admite funciones anónimas mediante una estructura sintáctica llamada bloque . Hay dos tipos de datos para bloques en Ruby. ProcLos se comportan de forma similar a los cierres , mientras que lambdalos se comportan de forma más análoga a una función anónima. [ 27 ] Cuando se pasa a un método, un bloque se convierte en un Proc en algunas circunstancias.

# Ejemplo 1: # Funciones puramente anónimas usando bloques. ex = [ 16 . 2 , 24 . 1 , 48 . 3 , 32 . 4 , 8 . 5 ] => [ 16 . 2 , 24 . 1 , 48 . 3 , 32 . 4 , 8 . 5 ] ex . sort_by { | x | x - x . to_i } # Ordenar por la parte fraccionaria, ignorando la parte entera. => [ 24 . 1 , 16 . 2 , 48 . 3 , 32 . 4 , 8 . 5 ]# Ejemplo 2: # Funciones de primera clase como un objeto explícito de Proc - ex = Proc . new { puts "¡Hola, mundo!" } => #<Proc:0x007ff4598705a0@(irb):7> ex . call ¡Hola , mundo! => nil# Ejemplo 3: # Función que devuelve un objeto de función lambda con parámetros def multiple_of? ( n ) lambda { | x | x % n == 0 } end => nil multiple_four = multiple_of? ( 4 ) => #<Proc:0x007ff458b45f88@(irb):12 (lambda)> multiple_four . call ( 16 ) => true multiple_four [ 15 ] => false

Óxido

En Rust , las funciones anónimas se denominan cierres. [ 28 ] Se definen utilizando la siguiente sintaxis:

|< parámetro - nombre > : < tipo >| -> < tipo - retorno > { < cuerpo > };

Por ejemplo:

sea ​​f = | x : i32 | -> i32 { x * 2 };

Sin embargo, con la inferencia de tipos, el compilador puede inferir el tipo de cada parámetro y el tipo de retorno, por lo que la forma anterior se puede escribir como:

sea ​​f = | x | { x * 2 };

En el caso de cierres con una sola expresión (es decir, un cuerpo con una sola línea) y tipo de retorno implícito, se pueden omitir las llaves:

sea ​​f = | x | x * 2 ;

Las clausuras sin parámetros de entrada se escriben de la siguiente manera:

let f = || println! ( "Hola, mundo!" );

Los cierres pueden pasarse como parámetros de entrada de funciones que esperan un puntero a función:

// Una función que toma un puntero a función como argumento y lo llama con // el valor '5'. fn apply ( f : fn ( i32 ) -> i32 ) -> i32 { // Sin punto y coma, para indicar un retorno implícito f ( 5 ) }fn main () { // Definiendo el cierre let f = | x | x * 2 ;println! ( "{}" , apply ( f )); // 10 println! ( "{}" , f ( 5 )); // 10 }

Sin embargo, puede ser necesario utilizar reglas complejas para describir cómo se capturan los valores en el cuerpo del cierre. Estas se implementan utilizando los rasgos Fn, FnMut, y : [ 29 ]FnOnce

  • Fn: el cierre captura por referencia ( &T). Se utilizan para funciones que aún pueden ser llamadas aunque solo tengan acceso por referencia (con &) a su entorno.
  • FnMut: el cierre captura por referencia mutable ( &mut T). Se utilizan para funciones que pueden ser llamadas si tienen acceso de referencia mutable (con &mut) a su entorno.
  • FnOnce: el cierre captura por valor ( T). Se utilizan para funciones que se llaman solo una vez.

Con estas características, el compilador capturará las variables de la manera menos restrictiva posible. [ 29 ] Ayudan a controlar cómo se mueven los valores entre ámbitos, lo cual es de suma importancia ya que Rust sigue una construcción de ciclo de vida para asegurar que los valores se "tomen prestados" y se muevan de manera predecible y explícita. [ 30 ]

A continuación se muestra cómo se puede pasar un cierre como parámetro de entrada utilizando el Fnrasgo:

// Una función que toma un valor de tipo F (que se define como // un tipo genérico que implementa el rasgo 'Fn', por ejemplo, un cierre) // y lo llama con el valor '5'. fn apply_by_ref < F > ( f : F ) -> i32 donde F : Fn ( i32 ) -> i32 { f ( 5 ) }fn main () { let f = | x | { println! ( "Obtuve el valor: {}" , x ); x * 2 }; // Aplica la función antes de imprimir su valor de retorno println! ( "5 * 2 = {}" , apply_by_ref ( f )); }// ~~ Salida del programa ~~ // Obtuve el valor: 5 // 5 * 2 = 10

La definición de función anterior también se puede abreviar para mayor comodidad de la siguiente manera:

fn apply_by_ref ( f : impl Fn ( i32 ) -> i32 ) -> i32 { f ( 5 ) }

Scala

En Scala , las funciones anónimas utilizan la siguiente sintaxis: [ 31 ]

( x : Int , y : Int ) => x + y

En ciertos contextos, como cuando una función anónima se pasa como parámetro a otra función, el compilador puede inferir los tipos de los parámetros de la función anónima y omitirlos en la sintaxis. En tales casos, también es posible usar una notación abreviada para funciones anónimas mediante el uso del guion bajo para introducir parámetros sin nombre.

val lista = Lista ( 1 , 2 , 3 , 4 ) lista . reduceLeft ( ( x , y ) => x + y ) // Aquí, el compilador puede inferir que los tipos de x e y son ambos Int. // Por lo tanto, no necesita anotaciones de tipo en los parámetros de la función anónima.lista . reduceLeft ( _ + _ ) // Cada guion bajo representa un nuevo parámetro sin nombre en la función anónima. // Esto da como resultado un equivalente aún más corto a la función anónima anterior.

Charla informal

En Smalltalk, las funciones anónimas se denominan bloques y se invocan (llaman) enviándoles un mensaje de tipo "valor". Si se van a pasar varios argumentos, se debe usar un mensaje "valor:...valor:" con el número correspondiente de argumentos de tipo valor.

Por ejemplo, en GNU Smalltalk ,

st > f := [ : x | x * x ] . f valor: 8 . 64 st> [ : x : y | x + y ] valor: 5 valor: 6 . 11

Los bloques de Smalltalk son técnicamente cierres, lo que les permite sobrevivir a su ámbito de definición y seguir haciendo referencia a las variables declaradas en ellos.

st > f := [ : a | [ : n | a + n ]] valor: 100 . a BlockClosure "devuelve el bloque interno, que suma 100 (capturado en la variable " a ") a su argumento." st> f valor: 1 . 101 st> f valor: 2 . 102

Rápido

En Swift , las funciones anónimas se denominan cierres. [ 32 ] La sintaxis tiene la siguiente forma:

{ ( parámetros ) -> tipo de retorno en la instrucción }

Por ejemplo:

{ ( s1 : String , s2 : String ) -> Bool in return s1 > s2 }

En aras de la brevedad y la expresividad, los tipos de parámetros y el tipo de retorno pueden omitirse si pueden inferirse:

{ s1 , s2 en retorno s1 > s2 }

De manera similar, Swift también admite sentencias de retorno implícitas para cierres de una sola sentencia:

{ s1 , s2 en s1 > s2 }

Por último, también se pueden omitir los nombres de los parámetros; cuando se omiten, los parámetros se referencian utilizando nombres de argumentos abreviados, que consisten en el símbolo $ seguido de su posición (por ejemplo, $0, $1, $2, etc.):

{ $0 > $1 }

Tcl

En Tcl , la aplicación de la función anónima de elevación al cuadrado a 2 se ve así: [ 33 ]

aplicar { x {expr { $x * $x }}} 2 # devuelve 4

Este ejemplo involucra dos candidatos para lo que significa ser una función en Tcl. El más genérico generalmente se llama prefijo de comando , y si la variable f contiene dicha función, entonces la forma de realizar la aplicación de la función f ( x ) sería

{ * } $f $x

donde {*}está el prefijo de expansión (nuevo en Tcl 8.5). El prefijo de comando en el ejemplo anterior es apply {x {expr {$x*$x}}} Los nombres de los comandos se pueden vincular a prefijos de comando mediante el interp aliascomando. Los prefijos de comando admiten currificación . Los prefijos de comando son muy comunes en las API de Tcl .

La otra opción para "función" en Tcl se suele llamar lambda y aparece en el {x {expr {$x*$x}}}ejemplo anterior. Esta parte almacena en caché la forma compilada de la función anónima, pero solo se puede invocar pasándola al applycomando. Las lambdas no admiten currificación, a menos que se combinen con un applyprefijo de comando. Las lambdas son poco comunes en las API de Tcl.

Vala

En Vala , las funciones anónimas se admiten como expresiones lambda. [ 34 ]

delegado int IntOp ( int x , int y );void main () { IntOp foo = ( x , y ) => x * y ; stdout.printf ( " %d \n " , foo ( 10 , 5 ) ); }

Visual Basic .NET

Visual Basic .NET 2008 introdujo las funciones anónimas mediante la sintaxis lambda. Gracias a la tipificación implícita, VB ofrece una sintaxis eficiente para las funciones anónimas. Al igual que en Python, en VB.NET las funciones anónimas deben definirse en una sola línea; no pueden ser instrucciones compuestas. Además, una función anónima en VB.NET debe ser propiamente una función de VB.NET Function, es decir, debe devolver un valor.

Dim foo = Function ( x ) x * x Console . WriteLine ( foo ( 10 ))

Visual Basic.NET 2010 añadió compatibilidad con expresiones lambda multilínea y funciones anónimas sin valor de retorno. Por ejemplo, una función para usar en un hilo.

Dim t As New System . Threading . Thread ( Sub () For n As Integer = 0 To 10 'Contar hasta 10 Console . WriteLine ( n ) 'Imprimir cada número Next End Sub ) t . Start ()

Referencias

  1. "Expresiones de declaración (usando la colección de compiladores GNU (GCC))" . gcc.gnu.org . Consultado el 12 de enero de 2022 .
  2. "Especificación del lenguaje para bloques — Documentación de Clang 13" . clang.llvm.org . Consultado el 14 de enero de 2022 .
  3. "Expresiones lambda (desde C++11) - cppreference.com" . en.cppreference.com . Consultado el 14 de enero de 2022 .
  4. 1 2 3 4 5 6 7 Skeet, Jon (23 de marzo de 2019). C# en profundidad . Manning. ISBN 978-1617294532.
  5. ^ Albahari , José (2022). C# 10 en pocas palabras . O'Reilly. ISBN 978-1-098-12195-2.
  6. "Especificación del lenguaje C# 5.0" . Centro de descargas de Microsoft .
  7. "Un recorrido por el lenguaje Dart" . dart.dev . Consultado el 24 de noviembre de 2020 .
  8. "Sintaxis de Erlang/Elixir: Un curso intensivo" . elixir-lang.github.com . Consultado el 24 de noviembre de 2020 .
  9. "Erlang -- Diversión" . erlang.org . Consultado el 24 de noviembre de 2020 .
  10. "Funciones anónimas en GoLang" . Documentación de GoLang . 9 de enero de 2020. Consultado el 24 de noviembre de 2020 .
  11. "Novedades de JDK 8" .
  12. 1 2 Tutoriales de Java: Expresiones Lambda , docs.oracle.com
  13. Oracle Corporation. "Capítulo 15. Expresiones" . docs.oracle.com . Oracle Corporation . Consultado el 31 de mayo de 2026 .
  14. "Capítulo 15. Expresiones" . docs.oracle.com .  
  15. "jdk/LambdaMethod.java" . GitHub .
  16. Oracle Corporation. "Clase SerializedLambda" . docs.oracle.com . Oracle Corporation . Consultado el 31 de mayo de 2026 .
  17. Oracle Corporation. "Formato serializado" . docs.oracle.com . Oracle Corporation . Consultado el 31 de mayo de 2026 .
  18. "Programación en Lua - Más sobre funciones" . Archivado del original el 14 de mayo de 2008. Consultado el 25 de abril de 2008 .
  19. "2.7. Funciones anónimas · GitBook" . www.cs.cornell.edu .
  20. cartermp. "Expresiones Lambda: La divertida palabra clave - F#" . docs.microsoft.com . Consultado el 24 de noviembre de 2020 .
  21. "Manual de Nim" . nim-lang.github.io .
  22. "perlsub - Subrutinas de Perl - Navegador de Perldoc" . perldoc.perl.org . Consultado el 24 de noviembre de 2020 .
  23. http://php.net/create_function La parte superior de la página lo indica con "(PHP 4 >= 4.0.1, PHP 5)"
  24. "PHP: rfc:closures" . wiki.php.net .
  25. "Predicados anónimos" .en la Referencia del lenguaje Visual Prolog
  26. "6. Expresiones — Documentación de Python 3.9.0" . docs.python.org . Consultado el 24 de noviembre de 2020 .
  27. Sosinski, Robert (21 de diciembre de 2008). "Understanding Ruby Blocks, Procs and Lambdas" . Reactive.IO. Archivado del original el 31 de mayo de 2014. Recuperado el 30 de mayo de 2014 .
  28. "Cierres - Rust por ejemplo" . doc.rust-lang.org .
  29. 1 2 "Como parámetros de entrada - Rust por ejemplo" . doc.rust-lang.org .
  30. "Tiempos de vida - Rust por ejemplo" . doc.rust-lang.org .
  31. "Sintaxis de funciones anónimas - Documentación de Scala" . Archivado del original el 23/07/2013 . Consultado el 31/12/2010 .
  32. "Cierres — El lenguaje de programación Swift (Swift 5.5)" . docs.swift.org .
  33. página del manual de aplicación , consultada el 06/09/2012.
  34. Manual de referencia de Vala , consultado el 9 de junio de 2021.