Homoiconicity ( homoikonicity , eng. homoiconicity , eng. homoiconic , kreikasta ὁμός - yhtäläinen, identtinen + "ikonisuus" - samankaltaisuussuhde merkin ja objektin välillä, johon tämä merkki osoittaa (ks. semiotiikka ) - vuorostaan, vrt. Kreikan εἰκόνα - "kuva", "kuva") on joidenkin ohjelmointikielten ominaisuus , jossa ohjelman rakenne on samanlainen kuin sen syntaksi , ja siksi ohjelman sisäinen esitys voidaan määrittää lukemalla tekstimerkinnät [ 1] . Jos kieli on homoikoninen, se tarkoittaa, että ohjelman tekstillä on sama rakenne kuin sen abstraktilla syntaksipuulla (eli AST ja syntaksi ovat isomorfisia ). Tämä mahdollistaa kaiken kielen koodin käytön ja käsittelyn datana käyttäen samaa esitystapaa.
Homoikonisessa kielessä ohjelmien ensisijainen esitys on myös tietorakenne itse kielen primitiivityypissä . Tämä tekee metaohjelmoinnista helpompaa kuin kielessä ilman tätä ominaisuutta, koska koodia voidaan tarkastella datana : heijastus kielessä (ohjelman rakenteen määrittäminen ajon aikana ) perustuu yhteen, homogeeniseen rakenteeseen, eikä sitä tarvitse käsitellä. useita erilaisia rakenteita, jotka syntyvät monimutkaisissa syntaktisissa rakenteissa. Toisin sanoen homoikonisuus on sitä, kun ohjelman lähdekoodi kirjoitetaan perustietorakenteeksi ja ohjelmointikieli osaa käyttää sitä.
Tyypillinen esimerkki on ohjelmointikieli Lisp , joka on suunniteltu helpottamaan luetteloiden käsittelyä ja jossa rakenne on annettu S-lausekkeina , jotka ovat sisäkkäisten listojen muodossa. Lisp-ohjelmat kirjoitetaan listoina; tuloksena on, että ohjelma voi käyttää omia toimintojaan käynnissä ollessaan sekä ohjelmoida itsensä uudelleen lennossa. Homoikoniset kielet sisältävät yleensä täyden tuen syntaktisille makroille , jolloin ohjelmoija voi ilmaista ohjelmointimuunnoksia ytimekkäästi. Esimerkkejä tällaisista ohjelmointikielistä ovat Clojure (moderni Lispin murre), Rebol ja Refal .
Termi mainittiin ensimmäisen kerran Doug McIlroyn [2] vuonna 1960 julkaisemassa artikkelissa , johon puolestaan viitattiin Calvin Mooresin ja Peter Deutsch vuoden 1965 artikkelissa, jossa omaisuus esitettiin TRAC - ohjelmoinnin avaimena. heidän kehittämänsä kieli [3] .
Alan Kay käytti ja on saattanut popularisoida termiä "homoiconicity" käyttäen sitä tohtorintyössään Lispin ja TRAC-kielen vastaavista ominaisuuksista [4] ja huomioi ohjelmien luettavuuskustannukset tässä lähestymistavassa: "kielellä kirjoitetut ohjelmat ne näyttävät kuningas Burna-Buriashin kirjeeltä sumerille , painettu babylonilaisella nuolenpäällä . "
Yksi homoikonisuuden eduista on, että kielen laajentaminen uusilla käsitteillä on yleensä helpompaa, koska koodia edustavaa dataa voidaan siirtää ohjelman meta- ja peruskerroksen välillä. Funktion abstrakti syntaksipuu voidaan rakentaa ja muokata metallikerroksen tietorakenteena ja sitten suorittaa . Voi olla paljon helpompaa selvittää, kuinka koodia käsitellään, koska se voi olla ymmärrettävämpää yksinkertaisena datana (koska kielen muoto on sama kuin sen tietomuoto).
Haittapuolena on myös tämän mahdollistava yksinkertaisuus: ainakin Lisp-tyyppisten listasuuntautuneiden kielten tapauksessa tämä voi päästä eroon monista visuaalisista vihjeistä, jotka auttavat ihmisiä visuaalisesti jäsentämään kielen rakenteita, ja tämä voi johtaa lisääntymiseen. kielen oppimiskäyrässä [5] . Katso myös essee "The Curse of Lisp" [6] saadaksesi kuvauksen puutteista.
Tyypillinen osoitus homoikonisuudesta on metaympyrälaskin .
Homoikoniset ohjelmointikielet:
Von Neumann-arkkitehtuurijärjestelmissä (mukaan lukien suurin osa nykyaikaisista tietokoneista) konekoodilla on myös tämä ominaisuus, kun muistissa on tavujen tietotyyppi.
Lisp käyttää S-lausekkeita datan ja koodin ulkoisena esityksenä. S-lausekkeita voidaan lukea primitiivisellä funktiolla READ, joka palauttaa Lisp-perustyypit: listat, merkit, numerot, merkkijonot. Lisp-primitiivinen funktio EVALkäyttää tätä koodia, joka esitetään Lisp-datana, arvioidakseen sivuvaikutuksia ja palauttaakseen tuloksen.
Esimerkki Lispin tiedoista on luettelo, joka käyttää erityyppisiä tietoja: (ali)luetteloita, merkkejä, merkkijonoja ja kokonaislukuja:
(( :nimi "john" :ikä 20 ) ( :nimi "mary" :ikä 18 ) ( :nimi "liisa" :ikä 22 ))Lisp koodi. Esimerkissä käytetään luetteloita, symboleja ja numeroita:
( * ( sin 1.1 ) ( cos 2.03 )) ; infiksissa: sin(1.1)*cos(2.03)Tällaisen lausekkeen luominen primitiivifunktiolla LISTja tuloksen liittäminen muuttujaan expression:
( setf lauseke ( lista '* ( lista 'sin 1.1 ) ( lista 'cos 2.03 )) ) -> ( * ( SIN 1.1 ) ( COS 2.03 )) ; Lisp palauttaa ja tulostaa tuloksen ( kolmas lauseke ) ; lausekkeen kolmas elementti -> ( COS 2.03 )Korvataan termi COSsanalla SIN:
( setf ( ensimmäinen ( kolmas lauseke )) 'SIN ) ; Lauseke on nyt (* (SIN 1.1) (SIN 2.03)).Suorita lauseke:
( eval lauseke ) -> 0,7988834Tulosta tämä lauseke merkkijonoon:
( tulosta merkkijonoon lauseke ) -> "(* (SIN 1.1) (SIN 2.03)"Vähennä lauseke merkkijonosta:
( lue merkkijonosta "(* (SIN 1.1) (SIN 2.03))" ) -> ( * ( SIN 1.1 ) ( SIN 2.03 )) ; palauttaa luettelon luetteloista, numeroista ja symboleista