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, xM . 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.

Lista över språk
Språk Stöd Anteckningar
ActionScript Grön fästingY
Ada Röd XN Uttrycksfunktioner är en del av Ada2012
ALGOL 68 Grön fästingY
APL Grön fästingY 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 Röd XN
Våldsamt slag Grön fästingY Ett bibliotek har skapats för att stödja anonyma funktioner i Bash.
C Röd XN 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# Grön fästingY
C ++ Grön fästingY Från C ++ 11 -standarden
CFML Grön fästingY Från Railo 4, ColdFusion 10
Clojure Grön fästingY
COBOL Röd XN Micro Focus 's icke-standardiserade Managed COBOL-dialekt stöder lambdas, som kallas anonyma delegater/metoder.
Ringla Grön fästingY
D Grön fästingY
Pil Grön fästingY
Delphi Grön fästingY
Dylan Grön fästingY
Eiffel Grön fästingY
Alm Grön fästingY
Elixir Grön fästingY
Erlang Grön fästingY
F# Grön fästingY
Excel Grön fästingY Excel -kalkylbladsfunktion, 2021 betaversion
Faktor Grön fästingY "Citat" stöder detta
Fortran Röd XN
Frink Grön fästingY
Grön fästingY
Gosu Grön fästingY
Häftig Grön fästingY
Haskell Grön fästingY
Haxe Grön fästingY
Java Grön fästingY Stöds i Java 8 . Se avsnittet Java -begränsningar nedan för mer information.
JavaScript Grön fästingY
Julia Grön fästingY
Kotlin Grön fästingY
Läspa Grön fästingY
Logtalk Grön fästingY
Lua Grön fästingY
PÅSSJUKA Röd XN
Mathematica Grön fästingY
Lönn Grön fästingY
MATLAB Grön fästingY
Maxima Grön fästingY
Nästa generations skal Grön fästingY
Nim Grön fästingY
OCaml Grön fästingY
Oktav Grön fästingY
Objekt Pascal Grön fästingY 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+) Grön fästingY Kallas block ; förutom Objective-C kan block också användas på C och C ++ vid programmering på Apples plattform.
OpenSCAD Grön fästingY Funktion Bokstavligt stöd introducerades med version 2021.01.
Pascal Röd XN
Perl Grön fästingY
PHP Grön fästingY 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 Röd XN
Pytonorm Grön fästingY Python stöder anonyma funktioner genom lambda -syntaxen, som endast stöder uttryck, inte uttalanden.
R Grön fästingY
Racket Grön fästingY
Raku Grön fästingY
Rexx Röd XN
RPG Röd XN
Rubin Grön fästingY Rubys anonyma funktioner, ärvda från Smalltalk , kallas block .
Rost Grön fästingY
Scala Grön fästingY
Schema Grön fästingY
Småprat Grön fästingY Smalltalts anonyma funktioner kallas block .
Standard ML Grön fästingY
Snabb Grön fästingY Swifts anonyma funktioner kallas Stängningar.
TypeScript Grön fästingY
Tcl Grön fästingY
Vala Grön fästingY
Visual Basic .NET v9 Grön fästingY
Visual Prolog v 7.2 Grön fästingY
WLanguage v25 Grön fästingY 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 Grön fästingY

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.

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" inte fglobalt 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.

  1. helt anonym, kallad som skapad
    { say "I got called" };
    
  2. 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
    
  3. currying
    sub add ($m, $n) { $m + $n }
    my $seven   = add(3, 4);
    my $add_one = &add.assuming(m => 1);
    my $eight   = $add_one($seven);
    
  4. 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