Ensiluokkaisia ​​toimintoja

Tietojenkäsittelytieteessä ohjelmointikielellä on ensiluokkaisia ​​funktioita , jos se käsittelee toimintoja ensimmäisen luokan objekteina . Tämä tarkoittaa erityisesti sitä, että kieli tukee funktioiden välittämistä argumenteiksi muille funktioille, niiden palauttamista muiden funktioiden tuloksena, niiden määrittämistä muuttujiin tai niiden tallentamista tietorakenteisiin [1] . Jotkut ohjelmointikielen teoreetikot pitävät tarpeellisena tukea myös anonyymejä toimintoja [2] . Kielessä, jossa on ensiluokkaisia ​​funktioita, funktioiden nimillä ei ole erityisasemaa, niitä käsitellään normaaleina arvoina, joiden tyyppi on funktio [3] . Termiä käytti ensimmäisenä Christopher Strachey "toimii ensiluokkaisina esineinä" yhteydessä 1960-luvun puolivälissä [4] .

Ensiluokkaiset funktiot ovat olennainen osa toiminnallista ohjelmointia , jossa korkeamman asteen funktioiden käyttö on vakiokäytäntö. Yksinkertainen esimerkki korkeamman asteen funktiosta on Map -funktio , joka ottaa funktion ja listan argumentteinaan ja palauttaa luettelon käytettyään funktiota luettelon jokaiseen elementtiin. Jotta ohjelmointikieli tukee karttaa , sen on tuettava ohitusfunktioita argumenttina.

Välittävien funktioiden toteuttamisessa argumentteina ja niiden palauttamisessa tuloksina on joitain vaikeuksia, erityisesti sisäkkäisiin ja anonyymeihin funktioihin lisättyjen ei-paikallisten muuttujien läsnä ollessa . Historiallisesti niitä on kutsuttu funarg-ongelmiksi englanninkielisestä "funktion argumentista" [5] . Varhaiset pakolliset ohjelmointikielet selvisivät näistä ongelmista luopumalla tuen palauttamista funktioista seurauksena tai jättämällä pois sisäkkäiset funktiot ja siten ei-paikalliset muuttujat (erityisesti C ). Lisp , yksi ensimmäisistä toiminnallisista ohjelmointikielistä, käyttää dynaamista scoping -lähestymistapaa , jossa ei-paikalliset muuttujat palauttavat näiden muuttujien lähimmän määritelmän kohtaan, jossa funktiota kutsuttiin, sen sijaan, missä se ilmoitettiin. Täysi tuki ensimmäisen asteen funktioiden leksikaaliselle kontekstille otettiin käyttöön Schemessä , ja siihen sisältyy funktioviittausten käsitteleminen sulkemisina pelkkien sijasta [4] , mikä puolestaan ​​edellyttää roskien keräämisen käyttöä .

Käsitteet

Tässä osiossa tarkastellaan, kuinka tietyt ohjelmointiidioomit toteutetaan toiminnallisissa kielissä ensimmäisen kertaluvun funktioilla ( Haskell ) verrattuna pakollisiin kieliin, joissa funktiot ovat toisen kertaluvun objekteja ( C ).

Korkeamman asteen funktiot: funktion välittäminen argumenttina

Kielessä, jossa funktiot ovat ensimmäisen kertaluvun objekteja, funktioita voidaan välittää argumenteina muille funktioille aivan kuten mikä tahansa muu arvo. Joten esimerkiksi Haskellissa :

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

Kielet, joissa funktiot eivät ole ensimmäisen asteen objekteja, mahdollistavat korkeamman asteen funktioiden toteuttamisen delegaattien avulla .

C -kielen osoittimet mahdollistavat tietyin rajoituksin korkeamman asteen funktioiden rakentamisen (voit välittää ja palauttaa nimetyn funktion osoitteen, mutta et voi luoda uusia toimintoja):

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

Anonyymit ja sisäkkäiset funktiot

Anonyymejä toimintoja tukevissa kielissä voit välittää tällaisen funktion argumenttina korkeamman asteen funktiolle:

pää = kartta ( \ x -> 3 * x + 1 ) [ 1 , 2 , 3 , 4 , 5 ]

Kielellä, joka ei tue anonyymejä toimintoja, sinun on ensin sidottava -funktio nimeen:

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

Ei-paikalliset muuttujat ja sulkemiset

Jos ohjelmointikieli tukee anonyymejä tai sisäkkäisiä toimintoja, on riittävän loogista olettaa, että ne viittaavat muuttujiin funktion rungon ulkopuolella:

pää = olkoon a = 3 b = 1 kartassa ( \ x - > a * x + b ) [ 1 , 2 , 3 , 4 , 5 ]

Kun funktiot esitetään puhtaassa muodossa, herää kysymys, kuinka arvot välitetään funktion rungon ulkopuolelle. Tässä tapauksessa suljin on rakennettava manuaalisesti, eikä tässä vaiheessa tarvitse puhua ensiluokkaisista toiminnoista.

typedef struct { int ( * f )( int , int , int ); int * a ; int * b ; } sulkeminen_t ; void map ( sulkeminen_t * sulkeminen , int x [], koko_t n ) { for ( int i = 0 ; i < n ; ++ i ) x [ i ] = ( * sulkeminen -> f )( * sulkeminen -> a , * sulkeminen -> b , x [ i ]); } int f ( int a , int b , int x ) { palauttaa a * x + b ; } void main () { intl [] = { 1 , 2 , 3 , 4 , 5 } ; int a = 3 ; int b = 1 ; sulkeminen_t sulkeminen = { f , &a , & b }; kartta ( & sulkeminen , l , 5 ); }

Korkeamman asteen funktiot: Palauttavat funktiot tuloksena

Toiminnon palauttaminen palauttaa itse asiassa sen sulkemisen. C-esimerkissä kaikki sulkemiseen sisältyvät paikalliset muuttujat menevät soveltamisalan ulkopuolelle heti, kun sulkemisen muodostava funktio palaa. Myöhemmin sulkemisen pakottaminen voi johtaa määrittelemättömään käyttäytymiseen.

Katso myös

Muistiinpanot

  1. Abelson, Harold ; Sussman, Gerald Jay Tietokoneohjelmien rakenne ja tulkinta  (englanniksi) . - MIT Press , 1984. - P. Osa 1.3 Abstraktioiden formulointi korkeamman asteen menetelmillä . - ISBN 0-262-01077-1 .
  2. Ohjelmointikielen pragmatiikka , Michael Lee Scott, osa 11.2 "Functional Programming".
  3. Roberto Ierusalimschy; Luiz Henrique de Figueiredo; Waldemar Celes. Lua 5.0:  n (uuspr.) käyttöönotto . Arkistoitu alkuperäisestä 23. kesäkuuta 2017.
  4. 1 2 Rod Burstall, "Christopher Strachey — Understanding Programming Languages", Higher-Order and Symbolic Computation 13:52 ( 2000)
  5. Joel Moses . "The Function of FUNCTION in LISP, eli miksi FUNARG-ongelmaa pitäisi kutsua ympäristöongelmaksi" Arkistoitu 3. huhtikuuta 2015 Wayback Machinessa . MIT AI Memo 199, 1970.

Kirjallisuus

Linkit