Első osztályú funkciók

A számítástechnikában egy programozási nyelvnek első osztályú függvényei vannak , ha a függvényeket első osztályú objektumként kezeli . Ez konkrétan azt jelenti, hogy a nyelv támogatja a függvények argumentumként való átadását más függvényeknek, más függvények eredményeként való visszaadását, változókhoz rendelését vagy adatstruktúrákban való tárolását [1] . Egyes programnyelvi teoretikusok szükségesnek tartják az anonim függvények támogatását is [2] . Az első osztályú függvényekkel rendelkező nyelvekben a függvényneveknek nincs különleges státusza, normál értékként kezelik, amelynek típusa függvény [3] . A kifejezést először Christopher Strachey használta az „első osztályú objektumként funkcionál” összefüggésben az 1960-as évek közepén [4] .

Az első osztályú függvények a funkcionális programozás szerves részét képezik , amelyben a magasabb rendű függvények használata általános gyakorlat. A magasabb rendű függvény egyszerű példája a Map függvény , amely egy függvényt és egy listát vesz argumentumaként, és visszaadja a listát, miután a függvényt a lista minden elemére alkalmazta. Ahhoz, hogy egy programozási nyelv támogassa a Map -et, támogatnia kell az átadási függvényeket argumentumként.

Némi nehézségek adódhatnak az átadott függvények argumentumként való megvalósítása és eredményként való visszaadása során, különösen a beágyazott és anonim függvényekben bevezetett nem lokális változók jelenlétében . Történelmileg funarg problémáknak nevezték őket , az angol "function argument" [5] szóból . A korai kötelező programozási nyelvek úgy oldották meg ezeket a problémákat, hogy emiatt megszüntették a visszatérő függvények támogatását, vagy a beágyazott függvényeket, és így a nem helyi változókat (különösen a C -t ). A Lisp , az egyik első funkcionális programozási nyelv, dinamikus hatókörű megközelítést alkalmaz , ahol a nem lokális változók a függvény hívási pontjához legközelebbi definíciót adják vissza, ahelyett, hogy deklarálták volna. Az elsőrendű függvények lexikális kontextusának teljes támogatását a Scheme vezette be, és magában foglalja a függvényhivatkozások lezárásként való kezelését a tiszta hivatkozások helyett [4] , ami viszont szükségessé teszi a szemétgyűjtés alkalmazását .

Fogalmak

Ez a rész azt vizsgálja, hogyan valósulnak meg bizonyos programozási idiómák az elsőrendű függvényekkel rendelkező funkcionális nyelvekben ( Haskell ), szemben az imperatív nyelvekkel, ahol a függvények másodrendű objektumok ( C ).

Magasabb rendű függvények: Függvény átadása argumentumként

Azokon a nyelveken, ahol a függvények elsőrendű objektumok, a függvények argumentumként adhatók át más függvényeknek, mint bármely más érték. Tehát például a Haskellben :

térkép :: ( a -> b ) -> [ a ] ​​​​-> [ b ] térkép f [] = [] térkép f ( x : xs ) = f x : térkép f xs

Azok a nyelvek, ahol a függvények nem elsőrendű objektumok, lehetővé teszik a magasabb rendű funkciók megvalósítását delegáltak használatával .

A C nyelv mutatói bizonyos megkötésekkel lehetővé teszik magasabb rendű függvények építését (egy elnevezett függvény címét átadhatja és visszaadhatja, de új függvényeket nem generálhat):

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

Névtelen és beágyazott függvények

Azon nyelveken, amelyek támogatják az anonim függvényeket, az ilyen függvényt argumentumként átadhatja egy magasabb rendű függvénynek:

= térkép ( \ x -> 3 * x + 1 ) [ 1 , 2 , 3 , 4 , 5 ]

Azon nyelveken, amelyek nem támogatják az anonim függvényeket, először az függvényt kell a névhez kötni :

int f ( int x ) { return 3 * x + 1 ; } int main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; térkép ( f , l , 5 ); }

Nem lokális változók és lezárások

Ha egy programozási nyelv támogatja a névtelen vagy beágyazott függvényeket, akkor elég logikus azt feltételezni, hogy ezek a függvénytörzsön kívüli változókra hivatkoznak:

= legyen a = 3 b = 1 a térképen ( \ x -> a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Amikor a függvényeket tiszta formában ábrázoljuk, felmerül a kérdés, hogyan lehet értékeket átadni a függvénytörzsön kívülre. Ebben az esetben manuálisan kell megépíteni a zárat, és ebben a szakaszban nem kell első osztályú funkciókról beszélni.

typedef struct { int ( * f )( int , int , int ); int * a ; int * b ; } záró_t ; void térkép ( záró_t * lezárás , int x [], méret_t n ) { for ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * bezárás -> f )( * bezárás -> a , * bezárás -> b , x [ i ]); } int f ( int a , int b , int x ) { return a * x + b ; } void main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; closure_t closure = { f , &a , & b }; térkép ( & bezárás , l , 5 ); }

Magasabb rendű függvények: függvények visszaadása eredményként

Egy függvény visszaadása valójában annak lezárását adja vissza. A C példában a lezárásba zárt összes helyi változó kikerül a hatókörből , amint a lezárást alkotó függvény visszatér. A bezárás későbbi kényszerítése meghatározatlan viselkedéshez vezethet.

Lásd még

Jegyzetek

  1. Abelson, Harold ; Sussman, Gerald Jay Számítógépes programok felépítése és értelmezése  (angol) . - MIT Press , 1984. - P. 1.3. szakasz Absztrakciók megfogalmazása magasabb rendű eljárásokkal . - ISBN 0-262-01077-1 .
  2. Programozási nyelv pragmatika , Michael Lee Scott, 11.2 "Funkcionális programozás" szakasz.
  3. Roberto Jerusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. A Lua 5.0  (neopr.) megvalósítása . Archiválva az eredetiből 2017. június 23-án.
  4. 1 2 Rod Burstall, "Christopher Strachey – A programozási nyelvek megértése", Higher-Order and Symbolic Computation 13:52 ( 2000)
  5. Joel Moses . "The Function of FUNCTION in LISP, avagy miért kell a FUNARG-problémát környezeti problémának nevezni" Archiválva : 2015. április 3., a Wayback Machine webhelyen . MIT AI Memo 199, 1970.

Irodalom

Linkek