Viitteellinen läpinäkyvyys

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 30. marraskuuta 2015 tarkistetusta versiosta . tarkastukset vaativat 9 muokkausta .

Viittauksen läpinäkyvyys ja referenssiläpinäkyvyys ovat tietokoneohjelmien osien ominaisuuksia . Lausekkeen sanotaan olevan viitteellisesti läpinäkyvä, jos se voidaan korvata vastaavalla arvolla muuttamatta ohjelman toimintaa. Viittauksellisesti läpinäkyvät funktiot arvioivat samat arvot samoilla argumenteilla. Tällaisia ​​funktioita kutsutaan puhtaiksi funktioiksi .

Matematiikassa kaikki funktiot ovat referenssisesti läpinäkyviä matemaattisen funktion määritelmän mukaan . Ohjelmoinnissa näin ei kuitenkaan aina ole. Jotta sanan "funktio" semanttiset assosiaatiot eivät olisi harhaanjohtavia, termejä " menettely " ja " metodi " käytetään usein. Funktionaalisessa ohjelmoinnissa huomioidaan vain viitteelliset läpinäkyvät funktiot. Jotkut ohjelmointikielet tarjoavat keinon taata viittauksen läpinäkyvyys. Jotkut toiminnalliset ohjelmointikielet tarjoavat viitteellisen läpinäkyvyyden kaikille toiminnoille.

Viittauksen läpinäkyvyyden merkitys on, että sen avulla ohjelmoija ja kääntäjä voivat perustella ohjelman käyttäytymistä uudelleenkirjoitusjärjestelmänä . Se voi auttaa validoinnissa, algoritmien yksinkertaistamisessa , koodin muokkaamisessa rikkomatta sitä tai koodin optimoinnissa muistiin tallentamisen , yhteisen alilausekkeen poistamisen , laiskan arvioinnin tai rinnastamisen avulla .

Koska linkin läpinäkyvyys vaatii samat tulokset mille tahansa syötejoukolle milloin tahansa, viitteellisesti läpinäkyvä lauseke on siksi deterministinen.

Historia

Tämä käsite (vaikka ei termi) näyttää saaneen alkunsa Alfred North Whiteheadilta ja Bertrand Russellin (1910-13) matematiikan periaatteista . Willard Van Orman Quine otti sen osaksi analyyttistä filosofiaa . Teoksessa Word and Object (1960) Quine antaa seuraavan määritelmän:

Suojausmoodi φ on viitteellisesti läpinäkyvä, jos aina kun yksittäisen termin t esiintyminen on puhtaasti viitteellinen termissä tai lauseessa ψ(t), se on myös puhtaasti referentiivinen sisältävässä sanassa tai lauseessa φ(ψ(t)).

Termi esiintyi nykyaikaisessa käytössään, kun keskusteltiin muuttujista ohjelmointikielissä, Christopher Stracheyn alkuperäisessä luentosarjassa.« Ohjelmointikielten peruskäsitteet» (1967). Bibliografiassa mainitaan Quinen sana ja esine.

Esimerkkejä ja vastaesimerkkejä

Jos kaikki lausekkeeseen liittyvät funktiot ovat puhtaita funktioita, lauseke on viitteellisesti läpinäkyvä. Myös joitain epäpuhtaita funktioita voidaan sisällyttää lausekkeeseen, jos niiden arvot hylätään ja niiden sivuvaikutukset eivät ole merkittäviä.

Harkitse funktiota, joka palauttaa tietoja jostain lähteestä. Pseudokoodissa kutsu tälle funktiolle voisi olla GetInput (Source), jossa Sourcevoi määrittää tietyn levytiedoston, näppäimistön jne. Jopa samoilla arvoilla Sourceperäkkäiset palautusarvot ovat erilaisia. Funktio GetInput ()ei siis ole deterministinen tai referenssillisesti läpinäkyvä.

Hienovaraisempi esimerkki on funktio, jossa on vapaa muuttuja , eli se riippuu jostakin syötteestä, jota ei ole eksplisiittisesti välitetty parametrina. Tämä ratkaistaan ​​sitten sääntöjen mukaisesti, jotka koskevat nimen sitomista ei-paikalliseen muuttujaan, kuten globaaliin muuttujaan , muuttujaan nykyisessä suoritusympäristössä (dynaamiselle sidokselle) tai muuttujalle sulkemiseen (staattista sidontaa varten). Koska tätä muuttujaa voidaan muuttaa muuttamatta parametrina välitettyjä arvoja, funktion myöhempien kutsujen tulokset voivat vaihdella, vaikka parametrit olisivat identtisiä. Pelkästään toiminnallisessa ohjelmoinnissa destruktiivinen osoitus ei kuitenkaan ole sallittua, joten jos vapaa muuttuja on staattisesti sidottu arvoon, funktiolla on silti referenssiläpinäkyvyys, koska ei-paikallinen muuttuja ei voi muuttua staattisen sitomisensa vuoksi.

Aritmeettiset operaatiot ovat viitteellisesti läpinäkyviä: voit esimerkiksi 5 * 5korvata 25. Itse asiassa kaikki funktiot matemaattisessa mielessä ovat viitteellisesti läpinäkyviä: sin (x)on läpinäkyviä, koska se antaa aina saman tuloksen jokaiselle tietylle x.

Tehtävät eivät ole läpinäkyviä. Esimerkiksi C - lauseke x = x + 1muuttaa muuttujalle määritettyä arvoa x. Olettaen, että xsillä on alun perin arvo 10, kaksi peräkkäistä lausekkeen arviointia antavat vastaavasti 11, ja 12. Ilmeisesti korvaaminen merkillä x = x + 1tai 11aiheuttaa 12sen, että lausekkeella on erilaiset arvot samalle lausekkeelle. Siksi tällainen ilmaisu ei ole viitteellisesti läpinäkyvä. Toiminnon, kuten esimerkiksi, kutsuminen on kuitenkin int plusone (int x) {return x + 1;}läpinäkyvää, koska se ei implisiittisesti muuta syöttöarvoa xeikä sillä siksi ole näitä sivuvaikutuksia .

Toiminto today()ei ole viitteellisesti läpinäkyvä. Jos lasket tämän funktion ja korvaat sen arvolla (esimerkiksi "1. tammikuuta 2001"), huomenna, käynnissä today(), ei saada samaa tulosta. Tämä johtuu siitä, että funktion palauttama arvo riippuu tilasta (päivämäärästä).

Kieleissä, joissa ei ole sivuvaikutuksia, kuten Haskell , voimme korvata tasa-arvon tasa-arvolla, koska f(x) = f(x)millä tahansa arvolla x. Mutta tämä ei koske kieliä, joilla on sivuvaikutuksia.

Kontrasti pakottavan ohjelmoinnin kanssa

Jos lausekkeen korvaaminen sen arvolla on voimassa vain tietyssä ohjelman kohdassa, lauseke ei ole viitteellisesti läpinäkyvä. Näiden sekvenssipisteiden määrittely ja järjestys on imperatiivisen ohjelmoinnin teoreettinen perusta ja osa imperatiivisen ohjelmointikielen semantiikkaa.

Koska viitteellisesti läpinäkyvä lauseke voidaan kuitenkin arvioida milloin tahansa, ei ole tarvetta määrittää sekvenssipisteitä tai mitään takuita arviointijärjestyksestä. Ohjelmointia ilman takuita arviointijärjestyksestä kutsutaan puhtaasti toiminnalliseksi ohjelmoimiseksi.

Yksi viittauksellisesti läpinäkyvään koodin kirjoittamisen eduista on, että se tekee kääntäjästä älykkäämmän, helpottaa staattisen koodin analysointia ja mahdollistaa automaattiset koodia parantavat muunnokset . Esimerkiksi C:llä ohjelmoitaessa suorituskyky heikkenee, jos silmukan sisällä on kallis funktiokutsu. Tämä siitä huolimatta, että tämän funktion kutsu voidaan siirtää silmukan ulkopuolelle ohjelman tulosten pysyessä ennallaan. Ohjelmoijan on sitten siirrettävä manuaalisesti puhelun sisältävä koodi, mahdollisesti luettavuuden kustannuksella. Jos kääntäjä voi kuitenkin määrittää, että funktio on viitteellisesti läpinäkyvä, se voi suorittaa tämän muunnoksen automaattisesti.

Viitteellisen läpinäkyvyyden omaavien kielten suurin haittapuoli on, että ne tekevät ilmaisuista, jotka luonnollisesti sopivat peräkkäiseen imperatiiviseen ohjelmointityyliin, hankalia ja vähemmän ytimekkäitä. Tällaiset kielet sisältävät usein mekanismeja, jotka helpottavat näitä tehtäviä säilyttäen samalla kielen puhtaasti toiminnallisen laadun, kuten tietyt kieliopilliset ilmaisut ja monadit .

Toinen esimerkki

Esimerkkinä käytetään kahta funktiota, joista toinen on viitteellisesti läpinäkymätön ja toinen viitteellisesti läpinäkyvä:

int globalValue = 0 ; int rq ( int x ) { globalValue ++ ; paluu x + globaaliarvo ; } int rt ( int x ) { paluu x + 1 ; }

Funktio rton viitteellisesti läpinäkyvä, mikä tarkoittaa, että rt(x) = rt(y)jos x = y. Esimerkiksi rt(6) = 6 + 1 = 7, rt(4) = 4 + 1 = 5jne. Emme kuitenkaan voi sanoa samaa :lle rq, koska se käyttää globaalia muuttujaa, jota se muokkaa.

Viittauksen läpinäkyvyys rqvaikeuttaa ohjelmien perustelemista. Oletetaan esimerkiksi, että haluamme selittää seuraavan lauseen:

kokonaisluku p = rq ( x ) + rq ( y ) * ( rq ( x ) -rq ( x ) );

Saattaa olla houkuttelevaa yksinkertaistaa tätä lausuntoa:

kokonaisluku p = rq ( x ) + rq ( y ) * ( 0 ); kokonaisluku p = rq ( x ) + 0 ; kokonaisluku p = rq ( x );

Tämä ei kuitenkaan toimi :lle rq(), koska jokainen esiintymä rq(x)arvioidaan eri arvoon. Muista, että palautettu arvo rqon otettu globaalista muuttujasta, jota ei välitetä ja joka muuttuu jokaisen kutsun yhteydessä rq. Tämä tarkoittaa, että matemaattiset identiteetit, kuten, x - x = 0 {\ displaystyle x-x = 0} x-x = 0eivät ole enää voimassa.

Tällaiset matemaattiset identiteetit pätevät viitteellisesti läpinäkyville funktioille, kuten rt.

Monimutkaisempaa analyysiä voidaan kuitenkin käyttää väitteen yksinkertaistamiseksi:

kokonaisluku a = globaaliArvo ; kokonaisluku p = x + a + 1 + ( y + a + 2 ) * ( x + a + 3 - ( x + a + 4 )); globalValue = globalValue + 4 ; kokonaisluku a = globaaliArvo ; kokonaisluku p = x + a + 1 + ( y + a + 2 ) * ( x + a + 3 - x - a - 4 )); globalValue = globalValue + 4 ; kokonaisluku a = globaaliArvo ; kokonaisluku p = x + a + 1 + ( y + a + 2 ) * - 1 ; globalValue = globalValue + 4 ; kokonaisluku a = globaaliArvo ; kokonaisluku p = x + a + 1 - y - a - 2 ; globalValue = globalValue + 4 ; kokonaisluku p = x - y - 1 ; globalValue = globalValue + 4 ;

Tämä vaatii enemmän vaiheita ja vaatii jonkin verran koodin ymmärtämistä, jota ei voida käyttää kääntäjän optimointiin.

Siksi viittauksen läpinäkyvyys antaa meille mahdollisuuden ajatella koodiamme, mikä johtaa luotettavampiin ohjelmiin, kykyyn löytää virheitä, joita emme löydä testauksen aikana, ja tietoisuuksista optimointimahdollisuuksista.