Prvotřídní funkce

V informaticeprogramovací jazyk prvotřídní funkce , pokud s funkcemi zachází jako s prvotřídními objekty . Konkrétně to znamená, že jazyk podporuje předávání funkcí jako argumentů jiným funkcím, jejich vracení jako výsledku jiných funkcí, jejich přiřazování k proměnným nebo jejich ukládání do datových struktur [1] . Někteří teoretici programovacích jazyků považují za nutné podporovat také anonymní funkce [2] . V jazycích s prvotřídními funkcemi nemají názvy funkcí žádný zvláštní status, jsou považovány za normální hodnoty, jejichž typem je funkce [3] . Termín byl poprvé použitChristopher Strachey v kontextu „funguje jako předměty první třídy“ v polovině 60. let [4] .

Funkce první třídy jsou nedílnou součástí funkcionálního programování , ve kterém je použití funkcí vyššího řádu standardní praxí. Jednoduchým příkladem funkce vyššího řádu by byla funkce Map , která bere funkci a seznam jako své argumenty a vrací seznam po aplikaci funkce na každý prvek seznamu. Aby programovací jazyk podporoval Map , musí podporovat předávání funkcí jako argument.

Při implementaci předávání funkcí jako argumentů a jejich vracení jako výsledků jsou určité potíže, zejména v přítomnosti nelokálních proměnných zavedených do vnořených a anonymních funkcí . Historicky se jim říkalo problémy funarg , z anglického „funkce argument“ [5] . Rané imperativní programovací jazyky tyto problémy obešly tím, že v důsledku toho zrušily podporu pro vracející se funkce nebo zrušily vnořené funkce, a tedy nelokální proměnné (zejména C ). Lisp , jeden z prvních funkcionálních programovacích jazyků, zaujímá dynamický rozsahový přístup , kde nelokální proměnné vracejí nejbližší definici těchto proměnných k bodu, ve kterém byla funkce volána, namísto bodu, ve kterém byla deklarována. Plná podpora lexikálního kontextu funkcí prvního řádu byla zavedena v Scheme a zahrnuje zacházení s odkazy na funkce jako s uzávěry namísto čistých [4] , což zase vyžaduje použití garbage collection .

Koncepty

Tato část se zabývá tím, jak jsou specifické programovací idiomy implementovány ve funkcionálních jazycích s funkcemi prvního řádu ( Haskell ) oproti imperativním jazykům, kde funkce jsou objekty druhého řádu ( C ).

Funkce vyššího řádu: Předání funkce jako argumentu

V jazycích, kde jsou funkce objekty prvního řádu, lze funkce předávat jako argumenty jiným funkcím stejně jako jakoukoli jinou hodnotu. Takže například v Haskellu :

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

Jazyky, kde funkce nejsou objekty prvního řádu, umožňují implementaci funkcí vyššího řádu pomocí delegátů .

Ukazatele v jazyce C s určitými omezeními umožňují vytvářet funkce vyššího řádu (můžete předat a vrátit adresu pojmenované funkce, ale nemůžete generovat nové funkce):

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

Anonymní a vnořené funkce

V jazycích, které podporují anonymní funkce, můžete takovou funkci předat jako argument funkci vyššího řádu:

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

V jazycích, které nepodporují anonymní funkce, musíte nejprve svázat funkci s názvem:

int f ( int x ) { návrat 3 * x + 1 ; } int main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; mapa ( f , l , 5 ); }

Nelokální proměnné a uzávěrky

Pokud programovací jazyk podporuje anonymní nebo vnořené funkce, je dost logické předpokládat, že budou odkazovat na proměnné mimo tělo funkce:

main = nechť a = 3 b = 1 na mapě ( \ x -> a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Když jsou funkce reprezentovány v čisté formě, vyvstává otázka, jak předávat hodnoty mimo tělo funkce. V tomto případě musíte uzávěr postavit ručně a v této fázi není nutné mluvit o prvotřídních funkcích.

typedef struct { int ( * f ) ( int , int , int ); int * a ; int * b ; } uzavření_t ; void mapa ( closure_t * closure , int x [], size_t n ) { for ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * uzávěr -> f )( * uzávěr -> a , * uzávěr -> b , x [ i ]); } int f ( int a , int b , int x ) { návrat a * x + b ; } void main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; closure_t closure = { f , &a , & b }; mapa ( & uzávěr , l , 5 ); }

Funkce vyššího řádu: Vrácení funkcí jako výsledek

Vrácení funkce ve skutečnosti vrací její uzavření. V příkladu C všechny lokální proměnné uzavřené v uzávěru přejdou mimo rozsah , jakmile se vrátí funkce, která tvoří uzávěr. Vynucení uzavření později může vést k nedefinovanému chování.

Viz také

Poznámky

  1. Abelson, Harold ; Sussman, Gerald Jay Struktura a interpretace počítačových programů  (anglicky) . - MIT Press , 1984. - P. Oddíl 1.3 Formulování abstrakce s postupy vyššího řádu . - ISBN 0-262-01077-1 .
  2. Pragmatika programovacího jazyka od Michaela Lee Scotta, sekce 11.2 "Funkční programování".
  3. Roberto Ierusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. Implementace Lua 5.0  (neopr.) . Archivováno z originálu 23. června 2017.
  4. 1 2 Rod Burstall, "Christopher Strachey—Understanding Programming Languages", Vyšší řád a symbolické výpočty 13:52 ( 2000)
  5. Joel Moses . „Funkce FUNKCE v LISPu aneb proč by se měl problém FUNARG nazývat problém prostředí“ Archivováno 3. dubna 2015 na Wayback Machine . MIT AI Memo 199, 1970.

Literatura

Odkazy