Anonym funktion - Anonymous function
I datorprogrammering är en anonym funktion ( funktionsbokstavlig , lambdaabstraktion , lambda -funktion , lambdauttryck eller block ) en funktionsdefinition som inte är bunden till en identifierare . Anonyma funktioner är ofta argument som skickas till funktioner av högre ordning eller används för att konstruera resultatet av en funktion av högre ordning som måste returnera en funktion. Om funktionen bara används en gång, eller ett begränsat antal gånger, kan en anonym funktion vara syntaktiskt lättare än att använda en namngiven funktion. Anonyma funktioner är allestädes närvarande i funktionella programmeringsspråk och andra språk med förstklassiga funktioner , där de fyller samma roll för funktionstypen som bokstäver gör för andra datatyper .
Anonyma funktioner har sitt ursprung i arbetet i Alonzo Church i hans uppfinning av lambda -kalkylen , där alla funktioner är anonyma, 1936, före elektroniska datorer. På flera programmeringsspråk introduceras anonyma funktioner med sökordet lambda , och anonyma funktioner kallas ofta lambdas eller lambda -abstraktioner. Anonyma funktioner har varit en funktion i programmeringsspråk sedan Lisp 1958, och ett växande antal moderna programmeringsspråk stöder anonyma funktioner.
Namn
Namnen "lambda -abstraktion", "lambda -funktion" och "lambda -uttryck" hänvisar till notationen av funktionsabstraktion i lambda -kalkyl, där den vanliga funktionen f ( x ) = M skulle skrivas (λ x . M ) ( M är ett uttryck som använder x ). Jämför med Python -syntaxen för .
lambda x: M
Namnet "pil funktion" avser den matematiska " kartor till " symbol, x ↦ M . Jämför med JavaScript -syntaxen för .
x => M
Användningsområden
Anonyma funktioner kan användas för att innehålla funktioner som inte behöver namnges och eventuellt för korttidsanvändning. Några anmärkningsvärda exempel inkluderar stängningar och currying .
Användningen av anonyma funktioner är en stilfråga. Att använda dem är aldrig det enda sättet att lösa ett problem; varje anonym funktion kan istället definieras som en namngiven funktion och kallas med namn. Vissa programmerare använder anonyma funktioner för att inkapsla specifik, icke återanvändbar kod utan att fylla koden med en massa små enradiga normala funktioner.
I vissa programmeringsspråk implementeras vanligtvis anonyma funktioner för mycket specifika ändamål, till exempel att binda händelser till återuppringning eller instansera funktionen för specifika värden, vilket kan vara mer effektivt, mer läsbart och mindre felaktigt än att ringa en mer generisk namngiven funktion .
Följande exempel är skrivna i Python 3.
Sortering
När du försöker sortera på ett icke-standardiserat sätt kan det vara lättare att innehålla sorteringslogiken som en anonym funktion istället för att skapa en namngiven funktion. De flesta språk har en generisk sorteringsfunktion som implementerar en sorteringsalgoritm som sorterar godtyckliga objekt. Denna funktion accepterar vanligtvis en godtycklig funktion som avgör hur man jämför om två element är lika eller om det ena är större eller mindre än det andra.
Tänk på att denna Python -kod sorterar en lista med strängar efter strängens längd:
>>> a = ['house', 'car', 'bike']
>>> a.sort(key=lambda x: len(x))
>>> a
['car', 'bike', 'house']
Den anonyma funktionen i detta exempel är lambda -uttrycket:
lambda x: len(x)
Den anonyma funktionen accepterar ett argument, xoch returnerar argumentets längd, som sedan används av sort()metoden som kriterier för sortering.
Grundsyntax för en lambda -funktion i Python är
lambda arg1, arg2, arg3, ...: <operation on the arguments returning a value>
Uttrycket som returneras av lambda -funktionen kan tilldelas en variabel och användas i koden på flera ställen.
>>> add = lambda a: a + a
>>> add(20)
40
Ett annat exempel skulle vara att sortera objekt i en lista efter klassens namn (i Python har allt en klass):
>>> a = [10, 'number', 11.2]
>>> a.sort(key=lambda x: x.__class__.__name__)
>>> a
[11.2, 10, 'number']
Observera att det 11.2har klassnamn " float", 10klassnamn " int" och 'number'klassnamn " str". Den sorterade ordningen är " float", " int", sedan " str".
Stängningar
Stängningar är funktioner som utvärderas i en miljö som innehåller bundna variabler . Följande exempel binder variabeln "tröskel" i en anonym funktion som jämför ingången med tröskeln.
def comp(threshold):
return lambda x: x < threshold
Detta kan användas som en slags generator för jämförelsefunktioner:
>>> 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
Det skulle vara opraktiskt att skapa en funktion för varje möjlig jämförelsesfunktion och kan vara för obekvämt för att hålla tröskeln kvar för vidare användning. Oavsett anledningen till att en stängning används, är den anonyma funktionen den enhet som innehåller den funktionalitet som gör jämförelsen.
Currying
Currying är processen för att ändra en funktion så att den snarare än att ta flera ingångar tar en enda ingång och returnerar en funktion som accepterar den andra ingången och så vidare. I det här exemplet omvandlas en funktion som utför division med vilket heltal som helst som utför division med ett uppsatt heltal.
>>> def divide(x, y):
... return x / y
>>> def divisor(d):
... return lambda x: divide(x, d)
>>> half = divisor(2)
>>> third = divisor(3)
>>> print(half(32), third(32))
16.0 10.666666666666666
>>> print(half(40), third(40))
20.0 13.333333333333334
Även om användningen av anonyma funktioner kanske inte är vanlig med curry, kan den fortfarande användas. I exemplet ovan genererar funktionsdelaren funktioner med en specificerad divisor. Funktionerna halva och tredje curry dela funktionen med en fast delare.
Delningsfunktionen bildar också en stängning genom att binda variabeln d.
Funktioner av högre ordning
En högre ordningsfunktion är en funktion som tar en funktion som ett argument. Detta används vanligtvis för att anpassa beteendet hos en generiskt definierad funktion, ofta en looping -konstruktion eller rekursionsschema. Anonyma funktioner är ett bekvämt sätt att ange sådana funktionsargument. Följande exempel finns i Python 3.
Karta
Kartfunktionen utför ett funktionsanrop på varje element i en lista. Följande exempel kvadrerar varje element i en array med en anonym funktion.
>>> a = [1, 2, 3, 4, 5, 6]
>>> list(map(lambda x: x*x, a))
[1, 4, 9, 16, 25, 36]
Den anonyma funktionen accepterar ett argument och multiplicerar det med sig själv (kvadraterar det). Ovanstående form avskräcks av språkets skapare, som hävdar att formen som presenteras nedan har samma innebörd och är mer anpassad till språkets filosofi:
>>> a = [1, 2, 3, 4, 5, 6]
>>> [x*x for x in a]
[1, 4, 9, 16, 25, 36]
Filtrera
Filterfunktionen returnerar alla element från en lista som utvärderar True när de skickas till en viss funktion.
>>> a = [1, 2, 3, 4, 5, 6]
>>> list(filter(lambda x: x % 2 == 0, a))
[2, 4, 6]
Den anonyma funktionen kontrollerar om argumentet till det är jämnt. Samma som med kartformuläret nedan anses vara mer lämpligt:
>>> a = [1, 2, 3, 4, 5, 6]
>>> [x for x in a if x % 2 == 0]
[2, 4, 6]
Vika ihop
En vikningsfunktion kör över alla element i en struktur (för listor vanligtvis från vänster till höger, en "vänster vikning", kallad reducei Python), och ackumulerar ett värde när det går. Detta kan användas för att kombinera alla element i en struktur till ett värde, till exempel:
>>> from functools import reduce
>>> a = [1, 2, 3, 4, 5]
>>> reduce(lambda x,y: x*y, a)
120
Detta presterar
Den anonyma funktionen här är multiplikationen av de två argumenten.
Resultatet av en vikning behöver inte vara ett värde. Istället kan både karta och filter skapas med fold. På kartan är värdet som ackumuleras en ny lista som innehåller resultaten av att tillämpa en funktion på varje element i den ursprungliga listan. I filtret är det ackumulerade värdet en ny lista som endast innehåller de element som matchar det givna villkoret.
Lista över språk
Följande är en lista över programmeringsspråk som stöder namnlösa anonyma funktioner helt eller delvis som någon variant, eller inte alls.
Denna tabell visar några allmänna trender. För det första är de språk som inte stöder anonyma funktioner ( C , Pascal , Object Pascal ) alla statiskt skrivna språk. Statiskt skrivna språk kan dock stödja anonyma funktioner. Till exempel är ML -språken statiskt skrivna och innehåller i grunden anonyma funktioner, och Delphi , en dialekt av Object Pascal , har utökats för att stödja anonyma funktioner, liksom C ++ (enligt standarden C ++ 11 ). För det andra har de språk som behandlar funktioner som förstklassiga funktioner ( Dylan , Haskell , JavaScript , Lisp , ML , Perl , Python , Ruby , Scheme ) i allmänhet anonymt funktionsstöd så att funktioner kan definieras och skickas lika enkelt som andra data typer.
| Språk | Stöd | Anteckningar |
|---|---|---|
| ActionScript |
|
|
| Ada |
|
Uttrycksfunktioner är en del av Ada2012 |
| ALGOL 68 |
|
|
| APL |
|
Dyalog, ngn och dzaima APL stöder fullt ut både dfns och tysta funktioner. GNU APL har ganska begränsat stöd för dfns. |
| Monteringsspråk |
|
|
| Våldsamt slag |
|
Ett bibliotek har skapats för att stödja anonyma funktioner i Bash. |
| C |
|
Support tillhandahålls i Clang och tillsammans med LLVM- kompilatorn-rt lib. GCC -stöd ges för en makroimplementering som möjliggör användning. Se nedan för mer information. |
| C# |
|
|
| C ++ |
|
Från C ++ 11 -standarden |
| CFML |
|
Från Railo 4, ColdFusion 10 |
| Clojure |
|
|
| COBOL |
|
Micro Focus 's icke-standardiserade Managed COBOL-dialekt stöder lambdas, som kallas anonyma delegater/metoder. |
| Ringla |
|
|
| D |
|
|
| Pil |
|
|
| Delphi |
|
|
| Dylan |
|
|
| Eiffel |
|
|
| Alm |
|
|
| Elixir |
|
|
| Erlang |
|
|
| F# |
|
|
| Excel |
|
Excel -kalkylbladsfunktion, 2021 betaversion |
| Faktor |
|
"Citat" stöder detta |
| Fortran |
|
|
| Frink |
|
|
| Gå |
|
|
| Gosu |
|
|
| Häftig |
|
|
| Haskell |
|
|
| Haxe |
|
|
| Java |
|
Stöds i Java 8 . Se avsnittet Java -begränsningar nedan för mer information. |
| JavaScript |
|
|
| Julia |
|
|
| Kotlin |
|
|
| Läspa |
|
|
| Logtalk |
|
|
| Lua |
|
|
| PÅSSJUKA |
|
|
| Mathematica |
|
|
| Lönn |
|
|
| MATLAB |
|
|
| Maxima |
|
|
| Nästa generations skal |
|
|
| Nim |
|
|
| OCaml |
|
|
| Oktav |
|
|
| Objekt Pascal |
|
Delphi, en dialekt av Object Pascal, stöder anonyma funktioner (formellt anonyma metoder ) inbyggt sedan Delphi 2009. Oxygene Object Pascal -dialekten stöder dem också. |
| Objective-C (Mac OS X 10.6+) |
|
Kallas block ; förutom Objective-C kan block också användas på C och C ++ vid programmering på Apples plattform. |
| OpenSCAD |
|
Funktion Bokstavligt stöd introducerades med version 2021.01. |
| Pascal |
|
|
| Perl |
|
|
| PHP |
|
Från och med PHP 5.3.0 stöds äkta anonyma funktioner. Tidigare stöddes endast delvis anonyma funktioner, vilket fungerade ungefär som C#: s implementering. |
| PL/I |
|
|
| Pytonorm |
|
Python stöder anonyma funktioner genom lambda -syntaxen, som endast stöder uttryck, inte uttalanden. |
| R |
|
|
| Racket |
|
|
| Raku |
|
|
| Rexx |
|
|
| RPG |
|
|
| Rubin |
|
Rubys anonyma funktioner, ärvda från Smalltalk , kallas block . |
| Rost |
|
|
| Scala |
|
|
| Schema |
|
|
| Småprat |
|
Smalltalts anonyma funktioner kallas block . |
| Standard ML |
|
|
| Snabb |
|
Swifts anonyma funktioner kallas Stängningar. |
| TypeScript |
|
|
| Tcl |
|
|
| Vala |
|
|
| Visual Basic .NET v9 |
|
|
| Visual Prolog v 7.2 |
|
|
| WLanguage v25 |
|
PCSofts W-språk som används av WinDev/WebDev/WinDev Mobile-paketet stöder anonyma funktioner från och med release 25 (2019) |
| Wolfram språk |
|
Exempel
Många språk stöder anonyma funktioner eller liknande.
APL
Endast vissa dialekter stöder anonyma funktioner, antingen som dfns , i tyst stil eller en kombination av båda.
f←{⍵×⍵} ⍝ As a dfn
f 1 2 3
1 4 9
g←⊢×⊢ ⍝ As a tacit 3-train (fork)
g 1 2 3
1 4 9
h←×⍨ ⍝ As a derived tacit function
h 1 2 3
1 4 9
C (icke-standardtillägg)
Den anonyma funktionen stöds inte av standard C -programmeringsspråk, men stöds av vissa C -dialekter, till exempel GCC och Clang .
GCC
GNU Compiler Collection (GCC) stöder anonyma funktioner, blandade av kapslade funktioner och uttalandeuttryck. Den har formen:
( { return_type anonymous_functions_name (parameters) { function_body } anonymous_functions_name; } )
Följande exempel fungerar bara med GCC. På grund av hur makron expanderas kan den l_bodyinte innehålla kommatecken utanför parenteser. GCC behandlar komma som en avgränsare mellan makroargument. Argumentet l_ret_typekan tas bort om det __typeof__är tillgängligt; i exemplet nedan kommer __typeof__on array att returnera testtype *, vilket kan avgränsas för det verkliga värdet om det behövs.
#include <stdio.h>
//* this is the definition of the anonymous function */
#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
{
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);
/* the anonymous function is given as function for the 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 stöder anonyma funktioner, kallade block , som har formen:
^return_type ( parameters ) { function_body }
Typen av blocken ovan är return_type (^)(parameters).
Med hjälp av ovannämnda blockförlängning och Grand Central Dispatch (libdispatch) kan koden se enklare ut:
#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");
};
/* Pass as a parameter to another function */
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), count_loop);
/* Invoke directly */
count_loop();
return 0;
}
Koden med block bör sammanställas med -fblocksoch länkas till-lBlocksRuntime
C ++ (sedan C ++ 11)
C ++ 11 stöder anonyma funktioner, kallade lambda -uttryck , som har formen:
[capture](parameters) -> return_type { function_body }
Detta är ett exempel på lambda -uttryck:
[](int x, int y) { return x + y; }
C ++ 11 stöder också nedläggningar , här kallade fångster. Captures definieras mellan hakparenteser [och ]i deklarationen av lambdauttryck. Mekanismen gör att dessa variabler kan fångas med värde eller genom referens. Följande tabell visar detta:
[] // No captures, the lambda is implicitly convertible to a function pointer.
[x, &y] // x is captured by value and y is captured by reference.
[&] // Any external variable is implicitly captured by reference if used
[=] // Any external variable is implicitly captured by value if used.
[&, x] // x is captured by value. Other variables will be captured by reference.
[=, &z] //z is captured by reference. Other variables will be captured by value.
Variabler som fångas efter värde är konstanta som standard. Att lägga till mutableefter parameterlistan gör dem icke-konstanta.
Följande två exempel visar användning av ett lambda -uttryck:
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; });
// Note that std::accumulate would be a way better alternative here...
Detta beräknar summan av alla element i listan. Variabeln totallagras som en del av lambdafunktionens stängning. Eftersom det är en referens till stackvariabeln totalkan den ändra dess värde.
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),
[&total, value, this](int x) { total += x * value * this->some_func(); });
Detta kommer att orsaka totalatt lagras som en referens, men valuekommer att lagras som en kopia.
Fångsten av thisär speciell. Det kan bara fångas med värde, inte genom referens. thiskan bara fångas om den närmaste omslutande funktionen är en icke-statisk medlemsfunktion. Lambda kommer att ha samma åtkomst som medlemmen som skapade den, när det gäller skyddade/privata medlemmar.
Om den thisfångas, antingen uttryckligen eller implicit, testas också omfattningen av de medföljande klassmedlemmarna. Åtkomst till medlemmar av thisbehöver inte uttrycklig användning av this->syntax.
Den specifika interna implementeringen kan variera, men förväntningen är att en lambda -funktion som fångar allt genom referens kommer att lagra den faktiska stackpekaren för den funktion som den skapas i, snarare än individuella referenser till stackvariabler. Eftersom de flesta lambdafunktionerna är små och lokala, är de troligen kandidater för inlining och behöver därför ingen extra lagring för referenser.
Om ett stängningsobjekt som innehåller referenser till lokala variabler åberopas efter det innersta blockets omfattning av dess skapande är beteendet odefinierat .
Lambdafunktioner är funktionsobjekt av en implementeringsberoende typ; denna typs namn är bara tillgängligt för kompilatorn. Om användaren vill ta en lambda -funktion som parameter måste parametertypen vara en malltyp, eller så måste de skapa ett std::functioneller ett liknande objekt för att fånga lambda -värdet. Användningen av autonyckelordet kan hjälpa till att lagra lambda -funktionen,
auto my_lambda_func = [&](int x) { /*...*/ };
auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });
Här är ett exempel på lagring av anonyma funktioner i variabler, vektorer och matriser; och skicka dem som namngivna parametrar:
#include <functional>
#include <iostream>
#include <vector>
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 (size_t i = 0; i < fv.size(); i++) {
std::cout << fv[i](2.0) << std::endl;
}
for (size_t 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;
}
Ett lambda -uttryck med en tom fångstspecifikation ( []) kan implicit omvandlas till en funktionspekare med samma typ som lambda deklarerades med. Så detta är lagligt:
auto a_lambda_func = [](int x) { /*...*/ };
void (* func_ptr)(int) = a_lambda_func;
func_ptr(4); //calls the lambda.
Den Boost biblioteket tillhandahåller sin egen syntax för lambda fungerar också, med hjälp av följande syntax:
for_each(a.begin(), a.end(), std::cout << _1 << ' ');
C#
I C# har stödet för anonyma funktioner fördjupats genom de olika versionerna av språkkompilatorn. Språket v3.0, som släpptes i november 2007 med .NET Framework v3.5, har fullt stöd för anonyma funktioner. C# kallar dem lambda -uttryck , efter den ursprungliga versionen av anonyma funktioner, lambda -kalkylen .
// the first int is the x' type // the second int is the return type // <see href="http://msdn.microsoft.com/en-us/library/bb549151.aspx" />Func<int,int> foo = x => x * x;Console.WriteLine(foo(7));
Även om funktionen är anonym kan den inte tilldelas en implicit typad variabel, eftersom lambda -syntaxen kan användas för att ange en anonym funktion eller ett uttrycksträd, och valet kan inte automatiskt bestämmas av kompilatorn. Exempelvis fungerar detta inte:
// will NOT compile!
var foo = (int x) => x * x;
Ett lambda -uttryck kan dock delta i typinferens och kan användas som ett metodargument , t.ex. för att använda anonyma funktioner med kartfunktionen tillgänglig med System.Collections.Generic.List(i ConvertAll()metoden):
// Initialize the list:
var values = new List<int>() { 7, 13, 4, 9, 3 };
// Map the anonymous function over all elements in the list, return the new list
var foo = values.ConvertAll(d => d * d) ;
// the result of the foo variable is of type System.Collections.Generic.List<Int32>
Tidigare versioner av C# hade mer begränsat stöd för anonyma funktioner. C# v1.0, som introducerades i februari 2002 med .NET Framework v1.0, gav delvis anonymt funktionsstöd genom att använda delegater . Denna konstruktion liknar något PHP -delegater. I C# 1.0 är delegater som funktionspekare som hänvisar till en uttryckligen namngiven metod inom en klass. (Men till skillnad från PHP är namnet onödigt vid tiden delegaten används.) C# v2.0, släppt i november 2005 med .NET Framework v2.0, introducerade begreppet anonyma metoder som ett sätt att skriva namnlösa inline -uttalande block som kan köras i en delegatanrop. C# 3.0 fortsätter att stödja dessa konstruktioner, men stöder också lambda -uttryckskonstruktionen.
Detta exempel kommer att kompilera i C# 3.0 och visar de tre formerna:
public class TestDriver
{
delegate int SquareDelegate(int d);
static int Square(int d)
{
return d * d;
}
static void Main(string[] args)
{
// C# 1.0: Original delegate syntax needed
// initializing with a named method.
SquareDelegate A = new SquareDelegate(Square);
System.Console.WriteLine(A(3));
// C# 2.0: A delegate can be initialized with
// inline code, called an "anonymous method". This
// method takes an int as an input parameter.
SquareDelegate B = delegate(int d) { return d * d; };
System.Console.WriteLine(B(5));
// C# 3.0. A delegate can be initialized with
// a lambda expression. The lambda takes an int, and returns an int.
// The type of x is inferred by the compiler.
SquareDelegate C = x => x * x;
System.Console.WriteLine(C(7));
// C# 3.0. A delegate that accepts one input and
// returns one output can also be implicitly declared with the Func<> type.
System.Func<int,int> D = x => x * x;
System.Console.WriteLine(D(9));
}
}
När det gäller C# 2.0 -versionen tar C# -kompilatorn kodblocket för den anonyma funktionen och skapar en statisk privat funktion. Internt får funktionen naturligtvis ett genererat namn; detta genererade namn är baserat på namnet på den metod där delegaten deklareras. Men namnet exponeras inte för applikationskod förutom genom att använda reflektion .
För C# 3.0 -versionen gäller samma mekanism.
ColdFusion Markup Language (CFML)
Använda fungera nyckelord:
fn = function(){
// statements
};
Eller använda en pilfunktion:
fn = () => {
// statements
};
fn = () => singleExpression // singleExpression is implicitly returned. There is no need for the braces or the return keyword
fn = singleParam => { // if the arrow function has only one parameter, there's no need for parentheses
// statements
}
fn = (x, y) => { // if the arrow function has zero or multiple parameters, one needs to use parentheses
// statements
}
CFML stöder alla uttalanden inom funktionens definition, inte bara uttryck.
CFML stöder rekursiva anonyma funktioner:
factorial = function(n){
return n > 1 ? n * factorial(n-1) : 1;
};
Anonyma CFML -funktioner implementerar stängning.
D
D använder inline delegater för att implementera anonyma funktioner. Hela syntaxen för en inline delegat är
return_type delegate(arguments){/*body*/}
Om entydig, returtypen och sökord delegat kan uteslutas.
(x){return x*x;}
delegate (x){return x*x;} // if more verbosity is needed
(int x){return x*x;} // if parameter type cannot be inferred
delegate (int x){return x*x;} // ditto
delegate double(int x){return x*x;} // if return type must be forced manually
Sedan version 2.0 tilldelar D stängningar på högen om inte kompilatorn kan bevisa att det är onödigt; det scopesökord kan användas för att tvinga stack tilldelning. Sedan version 2.058 är det möjligt att använda stenografi:
x => x*x;
(int x) => x*x;
(x,y) => x*y;
(int x, int y) => x*y;
En anonym funktion kan tilldelas en variabel och användas så här:
auto sqr = (double x){return x*x;};
double y = sqr(4);
Pil
Dart stöder anonyma funktioner.
var sqr = (x) => x * x;
print(sqr(5));
eller
print(((x) => x * x)(5));
Delphi
Delphi introducerade anonyma funktioner i version 2009.
program demo;
type
TSimpleProcedure = reference to procedure;
TSimpleFunction = reference to function(const x: string): Integer;
var
x1: TSimpleProcedure;
y1: TSimpleFunction;
begin
x1 := procedure
begin
Writeln('Hello World');
end;
x1; //invoke anonymous method just defined
y1 := function(const x: string): Integer
begin
Result := Length(x);
end;
Writeln(y1('bar'));
end.
PascalABC.NET
PascalABC.NET stöder anonyma funktioner med lambda -syntax
begin
var n := 10000000;
var pp := Range(1,n)
.Select(x->Rec(Random(),Random()))
.Where(p->sqr(p.Item1)+sqr(p.Item2)<1)
.Count/n*4;
Print(pp);
end.
Elixir
Elixir använder stängningen fn för anonyma funktioner.
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 använder en syntax för anonyma funktioner som liknar namngivna funktioner.
% Anonymous function bound to the Square variable
Square = fun(X) -> X * X end.
% Named function with the same functionality
square(X) -> X * X.
Gå
Go stöder anonyma funktioner.
foo := func(x int) int {
return x * x
}
fmt.Println(foo(10))
Haskell
Haskell använder en kortfattad syntax för anonyma funktioner (lambda -uttryck). Backslasen ska likna λ.
\x -> x * x
Lambda-uttryck är helt integrerade med typinferensmotorn och stöder alla syntaxer och funktioner i "vanliga" funktioner (förutom användning av flera definitioner för mönstermatchning, eftersom argumentlistan bara anges en gång).
map (\x -> x * x) [1..5] -- returns [1, 4, 9, 16, 25]
Följande är alla likvärdiga:
f x y = x + y
f x = \y -> x + y
f = \x y -> x + y
Haxe
I Haxe kallas anonyma funktioner lambda och använder syntaxen function(argument-list) expression;.
var f = function(x) return x*x;
f(8); // 64
(function(x,y) return x+y)(5,6); // 11
Java
Java stöder anonyma funktioner, med namnet Lambda Expressions , som börjar med JDK 8 .
Ett lambda -uttryck består av en kommaseparerad lista över de formella parametrarna som finns inom parentes, en piltoken ( ->) och en kropp. Datatyper för parametrarna kan alltid utelämnas, liksom parenteser om det bara finns en parameter. Kroppen kan bestå av ett uttalande eller ett uttalandeblock.
// with no parameter
() -> System.out.println("Hello, world.")
// with one parameter (this example is an identity function).
a -> a
// with one expression
(a, b) -> a + b
// with explicit type information
(long id, String name) -> "id: " + id + ", name:" + name
// with a code block
(a, b) -> { return a + b; }
// with multiple statements in the lambda body. It needs a code block.
// This example also includes two nested lambda expressions (the first one is also a closure).
(id, defaultPrice) -> {
Optional<Product> product = productList.stream().filter(p -> p.getId() == id).findFirst();
return product.map(p -> p.getPrice()).orElse(defaultPrice);
}
Lambda -uttryck konverteras till "funktionella gränssnitt" (definieras som gränssnitt som endast innehåller en abstrakt metod utöver en eller flera standard- eller statiska metoder), som i följande exempel:
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()));
}
}
I det här exemplet IntegerMathdeklareras ett funktionellt gränssnitt som kallas . Lambda -uttryck som implementeras IntegerMathöverförs till apply()metoden som ska köras. Standardmetoder som swapdefiniera metoder för funktioner.
Java 8 introducerade en annan mekanism som heter metodreferens ( ::operatören) för att skapa en lambda på en befintlig metod. En metodreferens anger inte antalet eller typerna av argument eftersom de extraheras från den abstrakta metoden i det funktionella gränssnittet.
IntBinaryOperator sum = Integer::sum;
I exemplet ovan IntBinaryOperatordeklarerar det funktionella gränssnittet en abstrakt metod int applyAsInt(int, int), så kompilatorn letar efter en metod int sum(int, int)i klassen java.lang.Integer.
Java -begränsningar
Java 8 lambdas har följande begränsningar:
- Lambdas kan kasta kontrollerade undantag, men sådana lambdas fungerar inte med de gränssnitt som används av Collection API.
- Variabler som är i omfattning där lambda deklareras får endast nås inuti lambda om de faktiskt är slutgiltiga, dvs om variabeln inte är muterad inuti eller utanför lambdas omfång.
JavaScript
JavaScript / ECMAScript stöder anonyma funktioner.
alert((function(x){
return x * x;
})(10));
ES6 stöder syntypen " pilfunktion ", där a => symbolen skiljer den anonyma funktionens parameterlista från kroppen:
alert((x => x * x)(10));
Denna konstruktion används ofta i Bookmarklets . Till exempel, om du vill ändra titeln på det aktuella dokumentet (synligt i fönstret i titelfältet ) till dess URL , kan följande bokmärke tycks fungera.
javascript:document.title=location.href;
Men eftersom tilldelningsuttalandet returnerar ett värde (själva webbadressen) skapar många webbläsare faktiskt en ny sida för att visa detta värde.
Istället kan en anonym funktion, som inte returnerar ett värde, användas:
javascript:(function(){document.title=location.href;})();
Funktionsuttalandet i det första (yttre) paret av paranteser deklarerar en anonym funktion, som sedan körs när den används med det sista paret av paranteser. Detta motsvarar nästan följande, som fyller miljön med till fskillnad från en anonym funktion.
javascript:var f = function(){document.title=location.href;}; f();
Använd void () för att undvika nya sidor för godtyckliga anonyma funktioner:
javascript:void(function(){return document.title=location.href;}());
eller bara:
javascript:void(document.title=location.href);
JavaScript har syntaktiska finesser för semantiken att definiera, åberopa och utvärdera anonyma funktioner. Dessa subliminella nyanser är en direkt följd av utvärderingen av parentetiska uttryck. Följande konstruktioner som kallas omedelbart påkallade funktionsuttryck illustrerar detta:
(function(){ ... }())
och
(function(){ ... })()
Konstruktionernas form representerar " function(){ ... }" genom fen parentes inom en parentes (f())och en parentes som tillämpas på en parentes (f)().
Observera den allmänna syntaktiska tvetydigheten för ett parentesuttryck, parentesiserade argument till en funktion och parenteserna kring de formella parametrarna i en funktionsdefinition. I synnerhet definierar JavaScript en ,(komma) operator i samband med ett parentesuttryck. Det är ingen slump att de syntaktiska formerna sammanfaller för ett uttryck och en funktions argument (ignorerar funktionens formella parametersyntax)! Om finte identifieras i konstruktionerna ovan blir de (())och ()(). Den första ger ingen syntaktisk antydan till någon inbyggd funktion men den andra MÅSTE utvärdera den första parentesen som en funktion för att vara laglig JavaScript. (Bortsett från: till exempel kan ()'s vara ([], {}, 42, "abc", funktion () {}) så länge uttrycket utvärderas till en funktion.)
En funktion är också en objektinstans (på samma sätt är objekt funktionsinstanser) och objektets bokstavsnoteringsklammar, {}för spänningskod, används när en funktion definieras på detta sätt (i motsats till att använda new Function(...)). I en mycket bred icke-rigorös bemärkelse (särskilt eftersom globala bindningar äventyras) kan en godtycklig sekvens av spända JavaScript-uttalanden {stuff}anses vara en fast punkt för
(function(){( function(){( ... {( function(){stuff}() )} ... )}() )}() )
Mer korrekt men med förbehåll
( function(){stuff}() ) ~=
A_Fixed_Point_of(
function(){ return function(){ return ... { return function(){stuff}() } ... }() }()
)
Observera konsekvenserna av den anonyma funktionen i JavaScript -fragmenten som följer:
-
function(){ ... }()utan omgivning()är i allmänhet inte lagligt -
(f=function(){ ... })"glömmer" intefglobalt till skillnad från(function f(){ ... })
- Prestanda statistik för att analysera utrymme och tid komplexiteten av funktionsanrop, anropsstacken, etc. i en JavaScript tolk motor implementera enkelt med de senaste anonym funktion konstruktioner. Av konsekvenserna av resultaten är det möjligt att härleda några av en motors rekursiva kontra iterativa implementeringsdetaljer, särskilt svansrekursion .
Julia
I Julia definieras anonyma funktioner med hjälp av syntaxen (arguments)->(expression),
julia> f = x -> x*x; f(8)
64
julia> ((x,y)->x+y)(5,6)
11
Läspa
Lisp och Scheme stöder anonyma funktioner med hjälp av "lambda" -konstruktionen, som är en referens till lambda -kalkyl . Clojure stöder anonyma funktioner med "fn" specialform och #() läsarsyntax.
(lambda (arg) (* arg arg))
Vanlig Lisp
Common Lisp har konceptet lambda uttryck. Ett lambda -uttryck skrivs som en lista med symbolen "lambda" som sitt första element. Listan innehåller sedan argumentlistan, dokumentationen eller deklarationerna och ett funktionsorgan. Lambda -uttryck kan användas inuti lambda -former och med den speciella operatörens "funktion".
(function (lambda (arg) (do-something arg)))
"funktion" kan förkortas som #'. Det finns också makro -lambda , som expanderar till en funktionsform:
; using sharp quote
#'(lambda (arg) (do-something arg))
; using the lambda macro:
(lambda (arg) (do-something arg))
En typisk användning av anonyma funktioner i Common Lisp är att skicka dem till högre ordningsfunktioner som mapcar , som tillämpar en funktion på varje element i en lista och returnerar en lista med resultaten.
(mapcar #'(lambda (x) (* x x))
'(1 2 3 4))
; -> (1 4 9 16)
Den lambda formen i Common Lisp tillåter en lambdauttryck som ska skrivas i ett funktionsanrop:
((lambda (x y)
(+ (sqrt x) (sqrt y)))
10.0
12.0)
Anonyma funktioner i Common Lisp kan också senare ges globala namn:
(setf (symbol-function 'sqr)
(lambda (x) (* x x)))
; which allows us to call it using the name SQR:
(sqr 10.0)
Schema
Schemas namngivna funktioner är helt enkelt syntaktiskt socker för anonyma funktioner bundna till namn:
(define (somename arg)
(do-something arg))
expanderar (och är likvärdig) till
(define somename
(lambda (arg)
(do-something arg)))
Clojure
Clojure stöder anonyma funktioner genom "fn" -formuläret:
(fn [x] (+ x 3))
Det finns också en läsarsyntax för att definiera en lambda:
#(+ % %2%3) ; Defines an anonymous function that takes three arguments and sums them.
Precis som Scheme är Clojures "namngivna funktioner" helt enkelt syntaktiskt socker för lambdas bundna till namn:
(defn func [arg] (+ 3 arg))
expanderar till:
(def func (fn [arg] (+ 3 arg)))
Lua
I Lua (ungefär som i Scheme) är alla funktioner anonyma. En namngiven funktion i Lua är helt enkelt en variabel som innehåller en referens till ett funktionsobjekt.
Således i Lua
function foo(x) return 2*x end
är bara syntaktiskt socker för
foo = function(x) return 2*x end
Ett exempel på att använda anonyma funktioner för omvänd ordning:
table.sort(network, function(a,b)
return a.name > b.name
end)
Wolfram Language, Mathematica
Den Wolfram Språk är programmeringsspråket Mathematica . Anonyma funktioner är viktiga vid programmering av de senare. Det finns flera sätt att skapa dem. Nedan följer några anonyma funktioner som ökar ett antal. Den första är den vanligaste. #1refererar till det första argumentet och &markerar slutet på den anonyma funktionen.
#1+1&
Function[x,x+1]
x \[Function] x+1
Så, till exempel:
f:= #1^2&;f[8]
64
#1+#2&[5,6]
11
Mathematica har också en extra konstruktion för att göra rekursiva anonyma funktioner. Symbolen '#0' avser hela funktionen. Följande funktion beräknar dess inmatningsfaktor:
If[#1 == 1, 1, #1 * #0[#1-1]]&
Till exempel skulle 6 faktorer vara:
If[#1 == 1, 1, #1 * #0[#1-1]]&[6]
720
MATLAB, Octave
Anonyma funktioner i MATLAB eller Octave definieras med hjälp av syntaxen @(argument-list)expression. Alla variabler som inte finns i argumentlistan ärvs från det omslutande omfånget och fångas upp av värde.
>> f = @(x)x*x; f(8)
ans = 64
>> (@(x,y)x+y)(5,6) % Only works in Octave
ans = 11
Maxima
I Maxima definieras anonyma funktioner med syntaxen lambda(argument-list,expression),
f: lambda([x],x*x); f(8);
64
lambda([x,y],x+y)(5,6);
11
ML
De olika dialekterna i ML stöder anonyma funktioner.
OCaml
Anonyma funktioner i OCaml är funktioner utan ett deklarerat namn. Här är ett exempel på en anonym funktion som multiplicerar sin input med två:
fun x -> x*2
I exemplet är kul ett nyckelord som anger att funktionen är en anonym funktion. Vi skickar in ett argument x och -> för att skilja argumentet från kroppen.
F#
F# stöder anonyma funktioner enligt följande:
(fun x -> x * x) 20 // 400
Standard ML
Standard ML stöder anonyma funktioner enligt följande:
fn arg => arg * arg
Nästa generations skal
Next Generation Shell har flera syntaxer för anonyma funktioner på grund av deras förekomst i språket och olika användningsfall.
Syntaxer:
f = X*X; f(8) # Result: 64
f = { A*B+C }; f(2,3,4) # Result: 10
f = F(x:Int, y:Int) x*y+2; f(3, 4) # Result: 14
f = "${X} is all about ${Y}"
f("programming", "semantics") # Result: "programming is all about semantics"
Användningsexempel på anonyma funktioner:
[0,1,2].map(X*2) # Result: [0,2,4]
data = {"a": "xxx", "b": "yyy"}
data.map("${X} is ${Y}") # Result: ["a is xxx", "b is yyy"]
Nim
Nim stöder anonyma funktioner med flera rader med flera uttryck.
var anon = proc (var1, var2: int): int = var1 + var2
assert anon(1, 2) == 3
Exempel på flera rader:
var anon = func (x: int): bool =
if x > 0:
result = true
else:
result = false
assert anon(9)
Anonyma funktioner kan skickas som inmatningsparametrar för andra funktioner:
var cities = @["Frankfurt", "Tokyo", "New York"]
cities.sort(
proc (x, y: string): int = cmp(x.len, y.len)
)
En anonym funktion är i grunden en funktion utan namn.
Perl
Perl 5
Perl 5 stöder anonyma funktioner enligt följande:
(sub { print "I got called\n" })->(); # 1. fully anonymous, called as created
my $squarer = sub { my $x = shift; $x * $x }; # 2. assigned to a variable
sub curry {
my ($sub, @args) = @_;
return sub { $sub->(@args, @_) }; # 3. as a return value of another function
}
# example of currying in Perl programming
sub sum { my $tot = 0; $tot += $_ for @_; $tot } # returns the sum of its arguments
my $curried = curry \&sum, 5, 7, 9;
print $curried->(1,2,3), "\n"; # prints 27 ( = 5 + 7 + 9 + 1 + 2 + 3 )
Andra konstruktioner tar bara block som argument, som tjänar en funktion som liknar lambda-funktioner för en parameter, men har inte samma parameterpassningskonvention som funktioner-@_ är inte inställd.
my @squares = map { $_ * $_ } 1..10; # map and grep don't use the 'sub' keyword
my @square2 = map $_ * $_, 1..10; # braces unneeded for one expression
my @bad_example = map { print for @_ } 1..10; # values not passed like normal Perl function
PHP
Före 4.0.1 hade PHP inget anonymt funktionsstöd.
PHP 4.0.1 till 5.3
PHP 4.0.1 introducerade det create_functionsom var det första anonyma funktionsstödet. Detta funktionsanrop gör en ny slumpmässigt namngiven funktion och returnerar sitt namn (som en sträng)
$foo = create_function('$x', 'return $x*$x;');
$bar = create_function("\$x", "return \$x*\$x;");
echo $foo(10);
Argumentlistan och funktionskroppen måste vara i enskilda citattecken, eller så måste dollartecknen undvikas. Annars antar PHP att " $x" betyder variabeln $xoch kommer att ersätta den i strängen (trots att den inte finns) istället för att lämna " $x" i strängen. För funktioner med citattecken eller funktioner med många variabler kan det bli ganska tråkigt att se till att den avsedda funktionskroppen är vad PHP tolkar.
Varje anrop av create_functiongör en ny funktion, som finns för resten av programmet, och som inte kan samlas in med skräp , med hjälp av minne i programmet irreversibelt. Om detta används för att skapa anonyma funktioner många gånger, t.ex. i en loop, kan det orsaka problem som minne uppblåsthet.
PHP 5.3
PHP 5.3 lade till en ny klass kallad Closureoch magisk metod __invoke()som gör att en klassinstans kan åberopas.
$x = 3;
$func = function($z) { return $z * 2; };
echo $func($x); // prints 6
I det här exemplet $funcär en förekomst av Closureoch echo $func($x)motsvarar echo $func->__invoke($x). PHP 5.3 efterliknar anonyma funktioner men det stöder inte sanna anonyma funktioner eftersom PHP-funktioner fortfarande inte är förstklassiga objekt.
PHP 5.3 stöder stängningar men variablerna måste uttryckligen anges som sådana:
$x = 3;
$func = function() use(&$x) { $x *= 2; };
$func();
echo $x; // prints 6
Variabeln $xär bunden av referens så att påkallandet av $funcmodifierar den och ändringarna är synliga utanför funktionen.
PHP 7.4
Pilfunktioner introducerades i PHP 7.4
$x = 3;
$func = fn($z) => $z * 2;
echo $func($x); // prints 6
Prologs dialekter
Logtalk
Logtalk använder följande syntax för anonyma predikat (lambda -uttryck):
{FreeVar1, FreeVar2, ...}/[LambdaParameter1, LambdaParameter2, ...]>>Goal
Ett enkelt exempel utan lediga variabler och med hjälp av ett listmappningspredikat är:
| ?- meta::map([X,Y]>>(Y is 2*X), [1,2,3], Ys).
Ys = [2,4,6]
yes
Currying stöds också. Ovanstående exempel kan skrivas som:
| ?- meta::map([X]>>([Y]>>(Y is 2*X)), [1,2,3], Ys).
Ys = [2,4,6]
yes
Visual Prolog
Anonyma funktioner (i allmänhet anonyma predikat ) introducerades i Visual Prolog i version 7.2. Anonyma predikat kan fånga värden från sammanhanget. Om den skapas i en objektmedlem kan den också komma åt objektstatus (genom att fånga This).
mkAdderreturnerar en anonym funktion, som har fångat argumentet Xi stängningen. Den returnerade funktionen är en funktion som lägger Xtill dess argument:
clauses
mkAdder(X) = { (Y) = X+Y }.
Pytonorm
Python stöder enkla anonyma funktioner via lambda -formuläret. Lambdas körbara kropp måste vara ett uttryck och kan inte vara ett uttalande, vilket är en begränsning som begränsar dess användbarhet. Värdet som returneras av lambda är värdet av det innehållande uttrycket. Lambda -formulär kan användas var som helst som vanliga funktioner kan. Men dessa begränsningar gör det till en mycket begränsad version av en normal funktion. Här är ett exempel:
>>> foo = lambda x: x * x
>>> foo(10)
100
I allmänhet uppmuntrar Python -konventionen till användning av namngivna funktioner definierade i samma omfattning som man vanligtvis kan använda anonyma funktioner på andra språk. Detta är acceptabelt eftersom lokalt definierade funktioner implementerar stängningens fulla kraft och är nästan lika effektiva som användningen av en lambda i Python. I det här exemplet kan den inbyggda effektfunktionen sägas ha blivit curried :
>>> def make_pow(n):
... def fixed_exponent_pow(x):
... return pow(x, n)
... return fixed_exponent_pow
...
>>> sqr = make_pow(2)
>>> sqr(10)
100
>>> cub = make_pow(3)
>>> cub(10)
1000
R
I R definieras de anonyma funktionerna med hjälp av syntaxen function(argument-list)expression.
> f <- function(x)x*x; f(8)
[1] 64
> (function(x,y)x+y)(5,6)
[1] 11
Raku
I Raku är alla block (även de som är associerade med if, while, etc.) anonyma funktioner. Ett block som inte används som en rvalue körs omedelbart.
- helt anonym, kallad som skapad
{ say "I got called" };
- tilldelad en variabel
my $squarer1 = -> $x { $x * $x }; # 2a. pointy block my $squarer2 = { $^x * $^x }; # 2b. twigil my $squarer3 = { my $x = shift @_; $x * $x }; # 2c. Perl 5 style
- currying
sub add ($m, $n) { $m + $n } my $seven = add(3, 4); my $add_one = &add.assuming(m => 1); my $eight = $add_one($seven);
- WhateverCode -objekt
my $w = * - 1; # WhateverCode object my $b = { $_ - 1 }; # same functionality, but as Callable block
Rubin
Ruby stöder anonyma funktioner med hjälp av en syntaktisk struktur som kallas block . Det finns två datatyper för block i Ruby. Procs beter sig på samma sätt som nedläggningar , medan lambdas beter sig mer analogt med en anonym funktion. När det överförs till en metod omvandlas ett block till en Proc under vissa omständigheter.
irb(main):001:0> # Example 1:
irb(main):002:0* # Purely anonymous functions using blocks.
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 } # Sort by fractional part, ignoring integer part.
=> [24.1, 16.2, 48.3, 32.4, 8.5]
irb(main):005:0> # Example 2:
irb(main):006:0* # First-class functions as an explicit object of Proc -
irb(main):007:0* ex = Proc.new { puts "Hello, world!" }
=> #<Proc:0x007ff4598705a0@(irb):7>
irb(main):008:0> ex.call
Hello, world!
=> nil
irb(main):009:0> # Example 3:
irb(main):010:0* # Function that returns lambda function object with parameters
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
Rost
I Rust kallas anonyma funktioner för nedläggningar. De definieras med följande syntax:
|<parameter-name>: <type>| -> <return-type> { <body> };
Till exempel:
let f = |x: i32| -> i32 { x * 2 };
Med typinferens kan kompilatorn emellertid utläsa typen av varje parameter och returtypen, så ovanstående formulär kan skrivas som:
let f = |x| { x * 2 };
Med stängningar med ett enda uttryck (dvs. en kropp med en linje) kan de lockiga hängslen utelämnas:
let f = |x| x * 2;
Stängningar utan ingångsparameter skrivs så här:
let f = || println!("Hello, world!");
Stängningar kan skickas som inmatningsparametrar för funktioner som förväntar sig en funktionspekare:
// A function which takes a function pointer as an argument and calls it with
// the value `5`.
fn apply(f: fn(i32) -> i32) -> i32 {
// No semicolon to indicate an implicit return
f(5)
}
fn main() {
// Defining the closure
let f = |x| x * 2;
println!("{}", apply(f)); // 10
println!("{}", f(5)); // 10
}
Man kan dock behöva komplexa regler för att beskriva hur värden i stängningens kropp fångas. De genomförs med hjälp av Fn, FnMutoch FnOnceegenskaper:
-
Fn: stängningen fångas genom referens (&T). De används för funktioner som fortfarande kan anropas om de bara har referensåtkomst (med&) till sin miljö. -
FnMut: stängningen fångas med muterbar referens (&mut T). De används för funktioner som kan anropas om de har muterbar referensåtkomst (med&mut) till sin miljö. -
FnOnce: stängningen fångas efter värde (T). De används för funktioner som bara kallas en gång.
Med dessa egenskaper kommer kompilatorn att fånga variabler på det minst restriktiva sättet som är möjligt. De hjälper till att styra hur värden flyttas mellan områden, vilket i stor utsträckning är viktigt eftersom Rust följer en livstidskonstruktion för att säkerställa att värden "lånas" och flyttas på ett förutsägbart och tydligt sätt.
Följande visar hur man kan passera en stängning som en ingångsparameter med hjälp av Fnegenskapen:
// A function that takes a value of type F (which is defined as
// a generic type that implements the `Fn` trait, e.g. a closure)
// and calls it with the value `5`.
fn apply_by_ref<F>(f: F) -> i32
where F: Fn(i32) -> i32
{
f(5)
}
fn main() {
let f = |x| {
println!("I got the value: {}", x);
x * 2
};
// Applies the function before printing its return value
println!("5 * 2 = {}", apply_by_ref(f));
}
// ~~ Program output ~~
// I got the value: 5
// 5 * 2 = 10
Scala
I Scala använder anonyma funktioner följande syntax:
(x: Int, y: Int) => x + y
I vissa sammanhang, som när en anonym funktion är en parameter som skickas till en annan funktion, kan kompilatorn utläsa typen av parametrar för den anonyma funktionen och de kan utelämnas i syntaxen. I sådana sammanhang är det också möjligt att använda en stenografi för anonyma funktioner med hjälp av understrykningstecknet för att införa namnlösa parametrar.
val list = List(1, 2, 3, 4)
list.reduceLeft( (x, y) => x + y )
// Here, the compiler can infer that the types of x and y are both Int.
// Thus, it needs no type annotations on the parameters of the anonymous function.
list.reduceLeft( _ + _ )
// Each underscore stands for a new unnamed parameter in the anonymous function.
// This results in an even shorter equivalent to the anonymous function above.
Småprat
I Smalltalk kallas anonyma funktioner block och de anropas (kallas) genom att skicka dem ett "värde" -meddelande. Om argument ska skickas måste ett "värde: ... värde:" -meddelande med motsvarande antal värde -argument användas.
Till exempel i GNU Smalltalk ,
st> f:=[:x|x*x]. f value: 8 .
64
st> [:x :y|x+y] value: 5 value: 6 .
11
Smalltalk -block är tekniskt stängda, vilket gör att de kan överleva sitt definierande omfång och fortfarande hänvisa till de variabler som deklareras däri.
st> f := [:a|[:n|a+n]] value: 100 .
a BlockClosure
"returns the inner block, which adds 100 (captured in "a" variable) to its argument."
st> f value: 1 .
101
st> f value: 2 .
102
Snabb
I Swift kallas anonyma funktioner för nedläggningar. Syntaxen har följande form:
{ (parameters) -> returnType in
statement
}
Till exempel:
{ (s1: String, s2: String) -> Bool in
return s1 > s2
}
För korthet och uttrycklighet kan parametertyper och returtyp utelämnas om dessa kan utläsas:
{ s1, s2 in return s1 > s2 }
På samma sätt stöder Swift också implicita avkastningsuttalanden för stängningar av ett uttalande:
{ s1, s2 in s1 > s2 }
Slutligen kan parameternamnen också utelämnas; när de utelämnas refereras parametrarna till med hjälp av stenografiska argumentnamn, bestående av $ -symbolen följt av deras position (t.ex. $ 0, $ 1, $ 2, etc.):
{ $0 > $1 }
Tcl
I Tcl ser tillämpningen av den anonyma kvadreringsfunktionen ut på 2 så här:
apply {x {expr {$x*$x}}} 2
# returns 4
Detta exempel involverar två kandidater för vad det innebär att vara en funktion i Tcl. Det mest generiska kallas vanligtvis ett kommandoprefix , och om variabeln f har en sådan funktion, skulle sättet att utföra funktionsapplikationen f ( x ) vara
{*}$f $x
var {*}är expansionsprefixet (nytt i Tcl 8.5). Kommandoprefixet i exemplet ovan är tillämpa {x {expr {$x*$x}}}
Kommandonamn kan bindas till kommandoprefix med hjälp av interp aliaskommandot. Kommandoprefix stöder currying . Kommandoprefix är mycket vanliga i Tcl API: er .
Den andra kandidaten för "funktion" i Tcl kallas vanligtvis en lambda och visas som en {x {expr {$x*$x}}}del av exemplet ovan. Detta är den del som cachar den sammanställda formen av den anonyma funktionen, men den kan bara åberopas genom att skickas till applykommandot. Lambdas stöder inte currying, såvida de inte är ihopkopplade med en för applyatt bilda ett kommandoprefix. Lambdas är sällsynta i Tcl API: er.
Vala
I Vala stöds anonyma funktioner som lambda -uttryck.
delegate 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 introducerade anonyma funktioner via lambda -formuläret. Kombinerat med implicit skrivning ger VB en ekonomisk syntax för anonyma funktioner. Som med Python, i VB.NET, måste anonyma funktioner definieras på en rad; de kan inte vara sammansatta uttalanden. Vidare måste en anonym funktion i VB.NET verkligen vara ett VB.NET Function- den måste returnera ett värde.
Dim foo = Function(x) x * x
Console.WriteLine(foo(10))
Visual Basic.NET 2010 har lagt till stöd för flerlinjiga lambdauttryck och anonyma funktioner utan returvärde. Till exempel en funktion för användning i en tråd.
Dim t As New System.Threading.Thread(Sub ()
For n As Integer = 0 To 10 'Count to 10
Console.WriteLine(n) 'Print each number
Next
End Sub
)
t.Start()
Se även
Referenser
externa länkar
- Anonyma metoder - när ska de användas? (blogg om anonym funktion i Delphi)
- Sammanställning av Lambda Expressions: Scala vs. Java 8
- php anonyma funktioner php anonyma funktioner
- Lambda fungerar på olika programmeringsspråk