Førsteklasses funktioner

Inden for datalogi har et programmeringssprog førsteklasses funktioner, hvis det behandler funktioner som førsteklasses objekter . Dette betyder især, at sproget understøtter at overføre funktioner som argumenter til andre funktioner, returnere dem som et resultat af andre funktioner, tildele dem til variabler eller gemme dem i datastrukturer [1] . Nogle programmeringssprogsteoretikere anser det for nødvendigt også at understøtte anonyme funktioner [2] . I sprog med førsteklasses funktioner har funktionsnavne ingen særlig status, de behandles som normale værdier, hvis type er en funktion [3] . Udtrykket blev første gang brugt af Christopher Strachey i forbindelse med "funktioner som førsteklasses objekter" i midten af ​​1960'erne [4] .

Førsteklasses funktioner er en integreret del af funktionel programmering , hvor brugen af ​​højere ordens funktioner er standardpraksis. Et simpelt eksempel på en højere-ordens funktion ville være Map -funktionen , som tager en funktion og en liste som sine argumenter og returnerer listen efter at have anvendt funktionen på hvert element i listen. For at et programmeringssprog skal understøtte Map , skal det understøtte videregivelse af funktioner som et argument.

Der er nogle vanskeligheder med at implementere videregivelse af funktioner som argumenter og returnere dem som resultater, især i tilstedeværelsen af ​​ikke-lokale variable introduceret i indlejrede og anonyme funktioner . Historisk set er de blevet kaldt funarg problems , fra det engelske "function argument" [5] . Tidlige imperative programmeringssprog kom uden om disse problemer ved at droppe støtte til returnering af funktioner som et resultat, eller ved at droppe indlejrede funktioner og dermed ikke-lokale variabler (især C ). Lisp , et af de første funktionelle programmeringssprog, har en dynamisk scoping -tilgang , hvor ikke-lokale variabler returnerer den nærmeste definition af disse variable til det punkt, hvor funktionen blev kaldt, i stedet for det punkt, hvor den blev erklæret. Fuld støtte til den leksikale kontekst af første-ordens funktioner blev introduceret i Scheme og involverer at behandle funktionsreferencer som lukninger i stedet for rene [4] , hvilket igen nødvendiggør brugen af ​​skraldindsamling .

Begreber

Dette afsnit ser på, hvordan specifikke programmeringssprog implementeres i funktionelle sprog med førsteordensfunktioner ( Haskell ) versus imperative sprog, hvor funktioner er andenordensobjekter ( C ).

Funktioner af højere orden: Sende en funktion som et argument

På sprog, hvor funktioner er første-ordens objekter, kan funktioner overføres som argumenter til andre funktioner ligesom enhver anden værdi. Så for eksempel i Haskell :

kort :: ( a -> b ) -> [ a ] ​​-> [ b ] kort f [] = [] kort f ( x : xs ) = f x : kort f xs

Sprog, hvor funktioner ikke er førsteordensobjekter, tillader , at funktioner af højere orden kan implementeres ved brug af delegerede .

PointereC -sproget giver dig med nogle begrænsninger mulighed for at bygge funktioner af højere orden (du kan videregive og returnere adressen på en navngivet funktion, men du kan ikke generere nye funktioner):

void map ( int ( * f )( int ), int x [], size_t n ) { for ( int i = 0 ; i < n ; i ++ ) x [ i ] = f ( x [ i ]); }

Anonyme og indlejrede funktioner

På sprog, der understøtter anonyme funktioner, kan du overføre en sådan funktion som et argument til en højere-ordens funktion:

hoved = kort ( \ x -> 3 * x + 1 ) [ 1 , 2 , 3 , 4 , 5 ]

På sprog, der ikke understøtter anonyme funktioner, skal du først binde -funktionen til navnet:

int f ( int x ) { returner 3 * x + 1 ; } int main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; kort ( f , l , 5 ); }

Ikke-lokale variabler og lukninger

Hvis et programmeringssprog understøtter anonyme eller indlejrede funktioner, er det logisk nok at antage, at de vil referere til variabler uden for funktionskroppen:

main = lad a = 3 b = 1 i kort ( \ x -> a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Når funktioner er repræsenteret i ren form, opstår spørgsmålet om, hvordan man sender værdier uden for funktionskroppen. I dette tilfælde skal du bygge lukningen manuelt, og på dette stadium er det ikke nødvendigt at tale om førsteklasses funktioner.

typedef struct { int ( * f )( int , int , int ); int * a ; int * b ; } closure_t ; void map ( closure_t * closure , int x [], size_t n ) { for ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * lukning -> f )( * lukning -> a , * lukning -> b , x [ i ]); } int f ( int a , int b , int x ) { returner a * x + b ; } void main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; closure_t closure = { f , &a , & b }; kort ( & lukning , l , 5 ); }

Funktioner i højere orden: Returnerer funktioner som resultat

At returnere en funktion returnerer faktisk dens lukning. I C-eksemplet vil alle lokale variabler, der er indesluttet i lukningen, gå uden for scope , så snart funktionen, der udgør lukningen, vender tilbage. At tvinge lukningen senere kan føre til udefineret adfærd.

Se også

Noter

  1. Abelson, Harold ; Sussman, Gerald Jay Struktur og fortolkning af computerprogrammer  (engelsk) . - MIT Press , 1984. - P. Afsnit 1.3 Formulering af abstraktioner med højere ordensprocedurer . - ISBN 0-262-01077-1 .
  2. Programmeringssprog pragmatik , af Michael Lee Scott, afsnit 11.2 "Funktionel programmering".
  3. Roberto Ierusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. Implementeringen af ​​Lua 5.0  (neopr.) . Arkiveret fra originalen den 23. juni 2017.
  4. 1 2 Rod Burstall, "Christopher Strachey—Understanding Programming Languages", Higher-Order and Symbolic Computation 13:52 ( 2000)
  5. Joel Moses . "Funktionen af ​​FUNCTION i LISP, eller hvorfor FUNARG-problemet bør kaldes miljøproblemet" Arkiveret 3. april 2015 på Wayback Machine . MIT AI Memo 199, 1970.

Litteratur

Links