Homoikonicitet ( homoiconicity , eng. homoiconicity , eng. homoiconic , af græsk ὁμός - lige, identisk + "ikonicitet" - lighedsforholdet mellem tegnet og objektet, som dette tegn peger på (se semiotik ) - på skift, fra jf. - Græsk εἰκόνα - "billede", "billede") er en egenskab for nogle programmeringssprog , hvor strukturen af programmet ligner dets syntaks , og derfor kan den interne repræsentation af programmet bestemmes ved at læse tekstmarkeringen [ 1] . Hvis et sprog er homoikonisk, betyder det, at programmets tekst har samme struktur som dets abstrakte syntakstræ (det vil sige, at AST og syntaks er isomorfe ). Dette gør det muligt at få adgang til al kode på sproget og behandle som data ved hjælp af den samme repræsentation.
I et homoikonisk sprog er den primære repræsentation af programmer også en datastruktur i selve sprogets primitive type . Dette gør metaprogrammering nemmere end i et sprog uden denne egenskab, da kode kan ses som data : refleksion i sproget (bestemmelse af strukturen af et program ved kørsel ) er baseret på en enkelt, homogen struktur, og der er ingen grund til at håndtere flere forskellige konstruktioner, der opstår i komplekse syntaktiske strukturer. Med andre ord er homoikonicitet, når kildekoden til et program er skrevet som en grundlæggende datastruktur, og programmeringssproget ved, hvordan man får adgang til det.
Et typisk eksempel er programmeringssproget Lisp , som er designet til at være nemt til listemanipulation, og hvor strukturen er givet som S-udtryk , som har form af indlejrede lister. Lisp-programmer skrives som lister; resultatet er, at programmet kan få adgang til sine egne funktioner, mens det kører, samt omprogrammere sig selv i farten. Homoikoniske sprog har en tendens til at inkludere fuld understøttelse af syntaktiske makroer , hvilket giver programmøren mulighed for at udtrykke programmeringstransformationer på en kortfattet måde. Eksempler på sådanne programmeringssprog er Clojure (en moderne dialekt af Lisp), Rebol og Refal .
Udtrykket blev første gang nævnt i en artikel fra 1960 af Doug McIlroy [2] , som igen blev refereret til i et papir fra 1965 af Calvin Moores og Peter Deutsch , hvor ejendommen blev præsenteret som nøglen til TRAC- programmeringen sprog de udviklede [3] .
Alan Kay brugte og kan have populariseret udtrykket "homoiconicity" ved at bruge det i sin ph.d.-afhandling om de respektive egenskaber ved Lisp og TRAC-sproget [4] og bemærkede læsbarhedsomkostningerne ved programmer i denne tilgang: "programmer skrevet i de ligner kong Burna-Buriashs brev til sumererne trykt i babylonsk kileskrift" .
En af fordelene ved at være homoikonisk er, at det har en tendens til at være lettere at udvide sproget med nye koncepter, da data, der repræsenterer kode, kan sendes mellem meta- og basislaget i et program. Det abstrakte syntakstræ for en funktion kan konstrueres og modificeres som en metallagsdatastruktur og derefter udføres . Det kan være meget nemmere at finde ud af, hvordan man manipulerer koden, da den kan være mere forståelig som simple data (da formatet på et sprog er det samme som dets dataformat).
Enkelheden, der tillader dette, er også en ulempe: i det mindste i tilfælde af Lisp-lignende listeorienterede sprog, kan dette slippe af med mange af de visuelle signaler, der hjælper folk visuelt at analysere sprogets konstruktioner, og dette kan føre til en stigning i indlæringskurven for sproget [5] . Se også essayet "The Curse of Lisp" [6] for en beskrivelse af manglerne.
En typisk demonstration af homoikonicitet er den metacirkulære regnemaskine .
Homoikoniske programmeringssprog:
I von Neumann arkitektursystemer ( herunder langt de fleste moderne computere) har maskinkode også denne egenskab med en datatype af bytes i hukommelsen.
Lisp bruger S-udtryk som en ekstern repræsentation af data og kode. S-udtryk kan læses ved hjælp af en primitiv funktion READ, der returnerer de grundlæggende Lisp-typer: lister, tegn, tal, strenge. En primitiv funktion i Lisp EVALbruger denne kode, repræsenteret som Lisp-data, til at evaluere bivirkninger og returnere resultatet.
Et eksempel på data i Lisp er en liste, der bruger forskellige typer data: (under)lister, tegn, strenge og heltal:
(( :navn "john" :alder 20 ) ( :navn "mary" :alder 18 ) ( :navn "alice" :alder 22 ))Lisp kode. Eksemplet bruger lister, symboler og tal:
( * ( sin 1.1 ) ( cos 2.03 )) ; i infix: sin(1.1)*cos(2.03)Oprettelse af et sådant udtryk med en primitiv funktion LISTog tildeling af resultatet til en variabel expression:
( setf udtryk ( liste '* ( liste ' sin 1.1 ) ( liste ' cos 2.03 )) ) -> ( * ( SIN 1.1 ) ( COS 2.03 )) ; Lisp vender tilbage og udskriver resultatet ( tredje udtryk ) ; det tredje element i udtrykket -> ( COS 2.03 )Udskiftning af udtryk COSmed SIN:
( setf ( første ( tredje udtryk )) 'SIN ) ; Udtrykket er nu (* (SIN 1.1) (SIN 2.03)).Kør udtryk:
( eval udtryk ) -> 0,7988834Udskriv dette udtryk til en streng:
( print-til-streng udtryk ) -> "(* (SIN 1.1) (SIN 2.03))"Træk et udtryk fra en streng:
( læs-fra-streng "(* (SIN 1.1) (SIN 2.03))" ) -> ( * ( SIN 1.1 ) ( SIN 2.03 )) ; returnerer en liste over lister, tal og symboler