Хомоиконичност (од грчких речи хомо што значи исто и иконе што значи представљање) у програмирању је власништво појединих програмских језика у којима је програмска структура слична његовој синтакси, а самим тим интерна репрезентација овог програма може се закључити читањем текста распореда.[1] Ако је језик homoiconicity, то значи да текст језика има исту структуру као апстрактно синтаксно стабло (тј AST и синтаксе су изоморфне). Ово омогућава да се свим кодовима у језику може приступити и и да могу да се трансформишу као подаци, користећи исту репрезентацију.

У homoiconic језику примарно представљање програма је такође структура података у примитивном типу самог језика. То чини метапрограмирање лакше него у језику без овог својства, јер код може да се третира као податак: рефлексија у језику (испитивање програмских лица на рантајму зависи од једне, хомогене структуре, и не мора да среди неколико различитих структура да ће се појавити у сложеној синтакси. На другачији начин, homoiconicity је место где је изворни код програма написан као основна структура података да би програмски језик знао како да му приступи.

Типичан, често цитирани пример је програмски језик Lisp, који је створен да буде лак за манипулацију листа и где је структуру дао S-изразима који су у облику угњеждених листа. Lisp програми су писани у облику спискова; резултат је да програм може приступити своје функције и процедуре у току рада, и програмски репрограм је у ходу. Homoiconic језици обично укључују пуну подршку синтаксних макроа омогућавајући програмеру да изрази програм трансформацију на концизан начин. Примери су програмски језици Clojure, што је савремени дијалект Lisp-а, Rebol-а и Refal-а.

Историја уреди

Оригинални извор је папир Макро инструкцја проширења компајлер језика,[2] према првом и утицајном папиру TRAC, текст за руковање језиком:[3]

Један од главних циљева дизајна је да улаз скрипта за TRAC (што се откуца од стране корисника) буде идентичан са текстом који води унутрашњу акцију TRAC процесора. Другим речима,  TRAC процедуре треба чувати у меморији као низ знакова тачно онако како их корисник откуца на тастатури. Ако TRAC процедуре саме развијају нове процедуре, те нове процедуре треба да буду наведене у истом сценарију. TRAC процесор у својој акцији тумачи овај сценарио као свој програм. Другим речима, TRAC преводилац програма (процесор) ефективно претвара рачунар у нови рачунар са новим програмским језиком - TRAC језик. У сваком тренутку, требало би да буде могуће да се прикаже програм или процедуралне информације у истом облику по ком ће TRAC процесор поступити током свог извршења. Пожељно је да унутрашњи карактер код буде идентичан, или врло сличан, спољној репрезентацији кода. У овој имплементацији TRAC-а, представљање интерног карактера се заснива на ASCII-у. Због TRAC процедуре и текст има исту заступљеност унутар и изван процесора, термин homoiconic се примењује, од речи хомо што значи исто и иконе што значи представљање.

[...]

Након предлога McCullough-а, W. S. на основу терминологије због Peirce, C. S. s McIlroy. M. D. "Макро инстикцја проширења компајлер језика", Comm. ACM. стр. 214-220; April, 1960.

Алан Кеј је користио и евентуално популаризовао термин "homoiconic" кроз његову употребу термина у његовој докторској дисертацији 1969-е:[4]

{{quote|Значајна група изузетака свих претходних система су интерактивни LISP [...] и TRAC. Оба су функционално оријентисана (једној листи, а други стринг), оба разговарају са корисником са једног језика, и оба су "homoiconic" у њиховој унутрашњој и спољашњој репрезентација што је у суштини исто. Оба имају способност да динамички створе нове функције које се тада могу разрадити на задовољство корисника.

Њихова једина велика мана је да програми писани у њима изгледају као писмо краља Burna-Buriašа на Сумерском рађено као вавилонско клинасто писмо![...]

Користи, предности и мане, уреди

Једна од предности homoiconicity-а је да проширени језик са новим концептима обично постаје једноставнији, јер подаци који представљају број се могу пренети између мета и подлоге програма. Апстрактно синтаксно стабло функције може се саставити и манипулисти њиме као структура података у мета слоју, а затим онда проценити. То може бити много лакше да се разуме како се манипулише кодом јер се може лакше разумети као једноставнији податак (од формата језика сама је као формат података).

Једноставност која омогућава ово такође представља недостатак: један блогер је тврдио да, барем у случају LISP-а-попут лист-оријентисаних језика, то може да уради у гостима са многим визуелним знаковима који помажу да људи визуелно анализирају и поимању језик, и да то може довести до стрмог учења  криве за језик.[5] Погледајте такође есеј "Lisp клетва"[6] за недостатке. Типична демонстрација homoiconicity-а је meta-circula евалуатор.

Примери уреди

Језици које су сматрани да су homoiconic укључују

У Фон Нојмановој архитектури система (укључујући велику већину опште намене рачунара данас), сирова код машина има ову особину, тип података који се бајтује у меморији.

Хомоиконичност у Lisp-у уреди

Lisp користи S-изразе као спољна репрезентација за податке и код.  S-изрази се могу прочитати са примитивне Lisp функције READ. READ враћа Lisp податке: листе, симболи, бројеви, стрингови. Примитивна READ функција EVAL користи Lisp код представљен као Lisp податак, израчунава нуспојаве и враћа резултат. Резултат ће бити одштампан на примитивној функцији PRINT, чиме се ствара спољни S-израз из Lisp података.

Lisp податак, листа употребом различитих типова података (суб)листе, симболи, стрингови и цели бројеви.

((:name "john" :age 20) (:name "mary" :age 18) (:name "alice" :age 22))

Lisp код. Овај пример користи листе, симболе и бројеве.

(* (sin 1.1) (cos 2.03)) ; у infix-у: sin(1.1)*cos(2.03)

Направите над изразом са примитивном Lisp листом функције и поставите променљиву EXPRESSION на резултат

(setf expression (list '* (list 'sin 1.1) (list 'cos 2.03)) ) 
-> (* (SIN 1.1) (COS 2.03)) ; Лисп враћа и штампа резултат

(third expression) ; Трећи елемент израза
-> (COS 2.03)

Промена COS термина за SIN

(setf (first (third expression)) 'SIN)
; Израз је сада (* (SIN 1.1) (SIN 2.03)).

Процените израз

(eval expression)
-> 0.7988834

Штампа израз у низу

(print-to-string expression)
-> "(* (SIN 1.1) (SIN 2.03))"

Читање израза низа

(read-from-string "(* (SIN 1.1) (SIN 2.03))")
-> (* (SIN 1.1) (SIN 2.03)) ; враћа списак листе, бројева и симбола

Homoiconicity у Prolog-у уреди

1 ?- X is 2*5.
X = 10.

2 ?- L = (X is 2*5), write_canonical(L).
is(_, *(2, 5))
L = (X is 2*5).

3 ?- L = (ten(X):-(X is 2*5)), write_canonical(L).
:-(ten(A), is(A, *(2, 5)))
L = (ten(X):-X is 2*5).

4 ?- L = (ten(X):-(X is 2*5)), assert(L).
L = (ten(X):-X is 2*5).

5 ?- ten(X).
X = 10.

6 ?-

На линији 4 стварамо нову клаузулу. Оператор ": -" одваја главу и тело клаузуле. Са тврдњом/1* ми је додајемо у постојећим клаузулама (да је додате у "базу"), тако да је можемо назвати касније. У другим језицима бисмо је назвали "стварањем неке функције у рантајму". Такође можемо уклонити клаузуле из базе података са укинутом/1, или повученом/1.

  • Број након имена клаузуле је број аргумената који можемо узети. (то се назива арити.)

Такође можемо упитати базу података да добије тело клаузулом:

7 ?- clause(ten(X),Y).
Y = (X is 2*5).

8 ?- clause(ten(X),Y), Y = (X is Z).
Y = (X is 2*5),
Z = 2*5.

9 ?- clause(ten(X),Y), call(Y).
X = 10,
Y = (10 is 2*5).

"позив" је аналоган Lisp's "eval" функције.

Homoiconicity у Rebo-у уреди

Концепт лечења кода као податак и манипулација и евалуација њега може доказати врло уредно у Rebol.. (Rebol, за разлику од Lisp-а, не захтева да се заградама раздвоје изрази).

Следи пример кода у Rebol-у (Имајте на уму да '>>' представља тумача упита; размаци између појединих елемената су додати за читљивости):

>> понављање i 3 [ стампање [ i "здраво" ] ]

Ово оцењује следећи излаз:

1 здраво
2 здраво
3 здраво

(понављање је, у ствари, уграђена функција у Rebol и није језик конструкција или кључне речи). Ставити код у заграде, преводилац то не процењује, али само га третира као блок који садржи речи:

[ понављање i 3 [ стампање [ i "здраво" ] ] ]

Овај блок има тип блока! и може даље бити додељен као вредност речи користећи оно што се чини да је синтакса за задатак, али заправо разуме преводиоца као посебну врсту (сет-реч!) и има облик речи, праћено двотачком :

>> блок1: [ понављање i 3 [ стампање [ i "здраво" ] ] ] ;; Додела вредности блок на реч `блок1`
== [repeat i 3 [print [i "hello"]]]
>> тип? блок1 ;; Процените врсту речи `блок1`
== блок!

Блок се и даље може тумачити помоћу функционалне обезбеђености у Rebol-у (као "eval" у Lisp).

Могуће је да испита елементе блока и промени њихове вредности, чиме мењају понашање кода ако је требало да се оцени:

>> блок1/3 ;; Трећи елемент блока
== 3
>> блок1/3: 5 ;; Подесите вредност 3. елемента у 5
== 5
>> проба блок1 ;; Показати промену блока
[ понављање i 5 [ стампање [ i "здраво" ] ] ]
== [ понављање i 5 [ стампање [ i "здраво" ] ] ]
>> до блок1 ;; Процените блок
1 здраво
2 здраво
3 здраво
4 здраво
5 здраво

Види још уреди

  • Concatenative програмски језик
  • Когнитивне димензије нотација, принципи дизајна за синтаксе програмских језика '

Референце уреди

  1. ^ Wheeler, David A. „Readable Lisp S-expressions”. 
  2. ^ Douglas McIlroy (1960) Macro Instruction Extensions of Compiler Languages
  3. ^ Calvin Mooers and L. Peter Deutsch (1965) TRAC, A Text-Handling Language
  4. ^ Alan Kay (1969) The Reactive Engine, PhD thesis (Accessed 20061229)
  5. ^ а б в Homoiconic languages Архивирано на сајту Wayback Machine (2. фебруар 2013), in true Blue blog at Oracle
  6. ^ The Lisp Curse, at Winestock Webdesign
  7. ^ а б в г д ђ е ж Homoiconic Languages
  8. ^ Shapiro, Ehud Y.; Sterling, Leon (1994). The art of Prolog: advanced programming techniques. Cambridge, Mass: MIT Press. ISBN 978-0-262-19338-2. 
  9. ^ S. Ramsay and B. Pytlik-Zillig, Code-Generation Techniques for XML Collections Interoperability Архивирано на сајту Wayback Machine (3. март 2016), Digital Humanities 2012 conference proceedings.
  10. ^ Wolfram Language Notes for Programming Language Experts

Литература уреди