Funcții de primă clasă

În informatică , un limbaj de programare are funcții de primă clasă dacă tratează funcțiile ca obiecte de primă clasă . În special, aceasta înseamnă că limbajul acceptă transmiterea de funcții ca argumente către alte funcții, returnarea lor ca rezultat al altor funcții, atribuirea lor variabilelor sau stocarea lor în structuri de date [1] . Unii teoreticieni ai limbajului de programare consideră că este necesar să suporte și funcții anonime [2] . În limbile cu funcții de primă clasă, numele funcțiilor nu au un statut special, ele sunt tratate ca valori normale al căror tip este o funcție [3] . Termenul a fost folosit pentru prima datăChristopher Strachey în contextul „funcționează ca obiecte de primă clasă” la mijlocul anilor 1960 [4] .

Funcțiile de primă clasă sunt o parte integrantă a programării funcționale , în care utilizarea funcțiilor de ordin superior este o practică standard. Un exemplu simplu de funcție de ordin superior ar fi funcția Map , care ia ca argumente o funcție și o listă și returnează lista după aplicarea funcției fiecărui element al listei. Pentru ca un limbaj de programare să accepte Map , trebuie să accepte funcții de trecere ca argument.

Există unele dificultăți în implementarea funcțiilor de trecere ca argumente și returnarea lor ca rezultate, în special în prezența variabilelor non-locale introduse în funcțiile imbricate și anonime . Din punct de vedere istoric, acestea au fost numite probleme funarg , din engleza „argument argument” [5] . Limbajele de programare imperative timpurii au rezolvat aceste probleme prin renunțarea la suportul pentru funcțiile returnate ca rezultat sau prin eliminarea funcțiilor imbricate și, prin urmare, a variabilelor non-locale (în special C ). Lisp , unul dintre primele limbaje de programare funcționale, adoptă o abordare dinamică , în care variabilele non-locale returnează cea mai apropiată definiție a acelor variabile la punctul în care funcția a fost apelată, în loc de punctul în care a fost declarată. Suportul complet pentru contextul lexical al funcțiilor de ordinul întâi a fost introdus în Scheme și implică tratarea referințelor de funcții ca închideri în loc de cele pure [4] , ceea ce, la rândul său, necesită utilizarea colectării gunoiului .

Concepte

Această secțiune analizează modul în care expresiile specifice de programare sunt implementate în limbaje funcționale cu funcții de ordinul întâi ( Haskell ) față de limbaje imperative în care funcțiile sunt obiecte de ordinul doi ( C ).

Funcții de ordin superior: trecerea unei funcții ca argument

În limbile în care funcțiile sunt obiecte de ordinul întâi, funcțiile pot fi transmise ca argumente altor funcții la fel ca orice altă valoare. Deci, de exemplu, în Haskell :

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

Limbile în care funcțiile nu sunt obiecte de ordinul întâi permit implementarea funcțiilor de ordin superior prin utilizarea delegaților .

Pointerii în limbajul C , cu unele restricții, vă permit să construiți funcții de ordin superior (puteți transmite și returna adresa unei funcții numite, dar nu puteți genera funcții noi):

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

Funcții anonime și imbricate

În limbile care acceptă funcții anonime, puteți transmite o astfel de funcție ca argument unei funcții de ordin superior:

principal = hartă ( \ x -> 3 * x + 1 ) [ 1 , 2 , 3 , 4 , 5 ]

În limbile care nu acceptă funcții anonime, mai întâi trebuie să legați funcția la numele:

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

Variabile non-locale și închideri

Dacă un limbaj de programare acceptă funcții anonime sau imbricate, este suficient de logic să presupunem că acestea se vor referi la variabile din afara corpului funcției:

principal = fie a = 3 b = 1 în hartă ( \ x -> a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Când funcțiile sunt reprezentate în formă pură, se pune întrebarea cum să se transmită valori în afara corpului funcției. În acest caz, trebuie să construiți manual închiderea, iar în această etapă nu este necesar să vorbiți despre funcții de primă clasă.

typedef struct { int ( * f )( int , int , int ); int * a ; int * b ; } closure_t ; void map ( closure_t * closure , int x [], size_t n ) { pentru ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * închidere -> f )( * închidere -> a , * închidere -> b , x [ i ]); } int f ( int a , int b , int x ) { returnează a * x + b ; } void main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; închidere_t închidere = { f , &a , & b }; harta ( & închidere , l , 5 ); }

Funcții de ordin superior: funcțiile returnate ca rezultat

Returnarea unei funcții returnează de fapt închiderea acesteia. În exemplul C, toate variabilele locale incluse în închidere vor ieși din domeniul de aplicare de îndată ce funcția care constituie închiderea revine. Forțarea închiderii mai târziu poate duce la un comportament nedefinit.

Vezi și

Note

  1. Abelson, Harold ; Sussman, Gerald Jay Structura și interpretarea programelor de calculator  (engleză) . - MIT Press , 1984. - P. Secţiunea 1.3 Formularea abstracţiilor cu proceduri de ordin superior . - ISBN 0-262-01077-1 .
  2. Pragmatica limbajului de programare , de Michael Lee Scott, secțiunea 11.2 „Programare funcțională”.
  3. Roberto Ierusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. Implementarea Lua 5.0  (neopr.) . Arhivat din original pe 23 iunie 2017.
  4. 1 2 Rod Burstall, „Christopher Strachey—Understanding Programming Languages”, Higher-Order and Symbolic Computation 13:52 ( 2000)
  5. Ioel Moise . „Funcția FUNCȚIEI în LISP sau de ce problema FUNARG ar trebui să fie numită problema mediului” Arhivată la 3 aprilie 2015 la Wayback Machine . MIT AI Memo 199, 1970.

Literatură

Link -uri