Jump to content

Гомоконичность

В компьютерном программировании гомоиконичность ( от греческих слов homo — «тот же» и icon — «представление») является свойством некоторых языков программирования . Язык является гомоиконичным , если написанной на нем программой можно манипулировать как данными, используя этот язык. [1] Таким образом, внутреннее представление программы можно получить, просто прочитав саму программу. Это свойство часто резюмируют, говоря, что язык рассматривает код как данные .

В гомоиконном языке первичным представлением программ является также структура данных в примитивном типе самого языка. [1] Это делает метапрограммирование проще, чем в языке без этого свойства: отражение в языке (исследование сущностей программы во время выполнения ) зависит от единой однородной структуры, и ему не приходится обрабатывать несколько разных структур, которые могли бы появиться в сложном синтаксисе. Гомоиконические языки обычно включают полную поддержку синтаксических макросов , что позволяет программисту кратко выражать преобразования программ.

Часто цитируемым примером является Lisp , который был создан для облегчения манипулирования списками и где структура задается S-выражениями , которые принимают форму вложенных списков и которыми можно манипулировать с помощью другого кода Lisp. [2] Другими примерами являются языки программирования Clojure (современный диалект Lisp), Rebol (также его преемник Red ), Refal , Prolog и, возможно, Julia см. в разделе «Методы реализации» ( подробнее ).

История [ править ]

Термин впервые появился в связи с языком программирования TRAC , разработанным Кэлвином Мурсом : [3]

Одна из основных целей разработки заключалась в том, чтобы входной сценарий TRAC (то, что вводится пользователем) был идентичен тексту, который управляет внутренними действиями процессора TRAC. Другими словами, процедуры TRAC должны храниться в памяти в виде строки символов точно в том виде, в котором пользователь набирает их с клавиатуры. Если процедуры ПРОФ сами по себе развивают новые процедуры, эти новые процедуры также должны быть указаны в том же сценарии. Процессор TRAC в своих действиях интерпретирует этот скрипт как свою программу. Другими словами, программа-переводчик TRAC (процессор) эффективно преобразует компьютер в новый компьютер с новым программным языком — языком TRAC. В любой момент должна быть возможность отображать программу или процедурную информацию в той же форме, в которой процессор TRAC будет воздействовать на нее во время ее выполнения. Желательно, чтобы внутреннее представление кода символа было идентично или очень похоже на представление внешнего кода. В настоящей реализации TRAC внутреннее представление символов основано на ASCII . Поскольку процедуры и текст TRAC имеют одинаковое представление внутри и снаружи процессора, применим термин гомоиконный, от слова homo, означающего то же самое, и значка, означающего представление.

Последнее предложение выше снабжено сноской 4, которая указывает на происхождение этого термина: [а]

Следуя предложению Маккалоу WS, основанному на терминологии Пирса, CS.

Исследователями, замешанными в этой цитате, могут быть нейрофизиолог и кибернетик Уоррен Стерджис Маккалок (обратите внимание на разницу в фамилии из заметки) и философ, логик и математик Чарльз Сандерс Пирс . [5] Пирс действительно использовал термин «икона» в своей «Семиотической теории». По Пирсу, в общении существует три вида знаков: значок, указатель и символ. Значок — это самое простое представление: значок физически похож на то, что он обозначает.

Алан Кей использовал и, возможно, популяризировал термин «гомоиконический», используя его в своей докторской диссертации 1969 года: [6]

Заметной группой исключений из всех предыдущих систем являются Interactive LISP [...] и TRAC. Оба функционально ориентированы (один список, другая строка), оба общаются с пользователем на одном языке и оба являются «гомоиконическими» в том смысле, что их внутреннее и внешнее представление по существу одинаковы. Они оба имеют возможность динамически создавать новые функции, которые затем могут быть доработаны по желанию пользователей. Их единственный большой недостаток состоит в том, что программы, написанные в них, похожи на письмо царя Бурнибуриаха шумерам, написанное вавилонской клинописью! [...]

Использование и преимущества [ править ]

Одним из преимуществ гомоиконичности является то, что расширение языка новыми концепциями обычно становится проще, поскольку данные, представляющие код, могут передаваться между мета- и базовым уровнем программы. Абстрактное синтаксическое дерево функции может быть составлено и обработано как структура данных на метауровне, а затем оценено . Гораздо проще понять, как манипулировать кодом, поскольку его легче понять как простые данные (поскольку формат самого языка соответствует формату данных).

Типичным примером гомоиконичности является метациклический оценщик .

Методы реализации [ править ]

Все системы с архитектурой фон Неймана , к которым сегодня относится подавляющее большинство компьютеров общего назначения, можно неявно охарактеризовать как гомоиконные из-за того, как в памяти выполняется необработанный машинный код, а тип данных в памяти — байты. Однако эту функцию также можно абстрагировать до уровня языка программирования.

Такие языки, как Лисп и его диалекты, [7] например Схема , [8] Clojure и Racket используют S-выражения для достижения гомоиконичности и считаются «самыми чистыми» формами гомоиконичности, поскольку эти языки используют одно и то же представление как для данных, так и для кода.

Другие языки предоставляют структуры данных для простого и эффективного управления кодом. Яркие примеры этой более слабой формы гомоиконичности включают Julia , Nim и Elixir .

Языки, которые часто считаются гомоиконическими, включают:

В Лиспе [ править ]

Lisp использует S-выражения в качестве внешнего представления данных и кода. S-выражения можно прочитать с помощью примитивной функции Lisp. READ. READ возвращает данные Lisp: списки, символы , числа, строки. Примитивная функция Лиспа EVAL использует код Lisp, представленный в виде данных Lisp, вычисляет побочные эффекты и возвращает результат. Результат будет напечатан примитивной функцией PRINT, который создает внешнее S-выражение из данных Lisp.

Данные Lisp — список, использующий различные типы данных: (под)списки, символы, строки и целые числа.

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

Лисп-код. В примере используются списки, символы и числа.

(* (sin 1.1) (cos 2.03))      ; in infix: sin(1.1)*cos(2.03)

Создайте приведенное выше выражение с помощью примитивной функции Lisp. LIST и установите переменную EXPRESSION к результату

(setf expression  (list '* (list 'sin 1.1) (list 'cos 2.03)) )  
-> (* (SIN 1.1) (COS 2.03))    ; Lisp returns and prints the result

(third expression)    ; the third element of the expression
-> (COS 2.03)

Измените COS срок до SIN

(setf (first (third expression)) 'SIN)
; The expression is now (* (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))     ; returns a list of lists, numbers and symbols

В Прологе [ править ]

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 мы создаем новое предложение. Оператор :- разделяет голову и тело предложения. С assert/1* мы добавляем его в существующие предложения (добавляем в «базу данных»), чтобы можно было вызвать его позже. На других языках мы бы назвали это «созданием функции во время выполнения». Мы также можем удалить предложения из базы данных с помощью abolish/1, или retract/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).

call аналогичен Лиспу eval функция.

В Реболе [ править ]

Концепция обработки кода как данных, а также манипулирование ими и их оценка могут быть очень четко продемонстрированы в Rebol . (Rebol, в отличие от Lisp, не требует скобок для разделения выражений).

Ниже приведен пример кода в Rebol (обратите внимание, что >> представляет подсказку переводчика; для удобства чтения добавлены пробелы между некоторыми элементами):

>> repeat i 3 [ print [ i "hello" ] ]

1 hello
2 hello
3 hello

( repeat на самом деле это встроенная функция в Rebol, а не языковая конструкция или ключевое слово).

Заключая код в квадратные скобки, интерпретатор не оценивает его, а просто воспринимает как блок, содержащий слова:

[ repeat i 3 [ print [ i "hello" ] ] ]

Этот блок имеет тип block! и, кроме того, может быть присвоено как значение слова, используя то, что кажется синтаксисом присваивания, но на самом деле понимается интерпретатором как специальный тип ( set-word!) и принимает форму слова, за которым следует двоеточие:

>> block1: [ repeat i 3 [ print [ i "hello" ] ] ] ;; Assign the value of the block to the word `block1`
== [repeat i 3 [print [i "hello"]]]
>> type? block1 ;; Evaluate the type of the word `block1`
== block!

Блок по-прежнему можно интерпретировать с помощью do функция, предоставляемая в Rebol (аналогично eval в Лиспе ).

Можно опрашивать элементы блока и изменять их значения, тем самым изменяя поведение кода при его оценке:

>> block1/3 ;; The third element of the block
== 3
>> block1/3: 5 ;; Set the value of the 3rd element to 5
== 5
>> probe block1 ;; Show the changed block
== [repeat i 5 [print [i "hello"]]]
>> do block1 ;; Evaluate the block
1 hello
2 hello
3 hello
4 hello
5 hello

См. также [ править ]

Примечания [ править ]

  1. ^ Предыдущие версии этой страницы Википедии за 2006–2023 годы объединяли несвязанное примечание 5 в приведенном выше документе TRAC, в результате чего возникло неверное утверждение о том, что термин «гомоиконический» возник в статье Дугласа Макилроя по обработке макросов. В этой статье не упоминается никакой терминологии, даже отдаленно похожей; его влияние на работу ПРОФ носит иной характер. Это утверждение с тех пор было повторено некоторыми источниками. [4]

Ссылки [ править ]

  1. ^ Jump up to: а б Черавола, Антонелло; Жублен, Франк (2021). «От JSON к JSEN через виртуальные языки» . Открытый журнал веб-технологий . 8 (1): 1–15. В гомоиконичном языке первичным представлением программ является также структура данных в примитивном типе самого языка.
  2. ^ Уилер, Дэвид А. «Читаемые S-выражения Lisp» .
  3. ^ Мурс, Китай ; Дойч, LP (1965). «TRAC, язык обработки текста». Труды ACM '65 Материалы 20-й национальной конференции 1965 года . стр. 229–246. дои : 10.1145/800197.806048 .
  4. ^ Маннарт, Хервиг; МакГроарти, Крис; Галлант, Скотт; Де Кок, Коэн; Галлогично, Джим; Раваль, Ануп; Снавли, Кейт (2022). «На пути к масштабируемому совместному метапрограммированию: пример интеграции двух сред метапрограммирования» (PDF) . Международный журнал достижений в области программного обеспечения . 15 : 128–140. ISSN   1942-2628 .
  5. ^ «Не говори «гомоикон» » . Выражения перемен . 1 марта 2018 г.
  6. ^ Кей, Алан (1969). Реактивный двигатель (доктор философии). Университет Юты.
  7. ^ Jump up to: а б с д и ж г час я Гомоиконические языки
  8. ^ Jump up to: а б Гомоиконические языки (в архиве) в true Blue в Oracle блоге
  9. ^ «Шипучий эликсир» . 8thlight.com . Эликсир, на первый взгляд, не является гомоиконом. Однако синтаксис на поверхности — это всего лишь фасад гомоиконической структуры, лежащей под ней.
  10. ^ «Зачем мы создали Юлю» . julialang.org . Нам нужен гомоиконический язык с настоящими макросами, такими как Lisp, но с очевидными, знакомыми математическими обозначениями, такими как Matlab.
  11. ^ «метапрограммирование» . docs.julialang.org . Как и Лисп, Джулия представляет свой собственный код как структуру данных самого языка.
  12. ^ Шапиро, Эхуд Ю.; Стерлинг, Леон (1994). Искусство Пролога: передовые методы программирования . МТИ Пресс. ISBN  0-262-19338-8 .
  13. ^ Рамзи, С.; Пытлик-Зиллиг, Б. (2012). «Методы генерации кода для совместимости XML-коллекций» . dh2012 Материалы конференции по цифровым гуманитарным наукам .
  14. ^ «Заметки для знатоков языков программирования» . Язык Вольфрам . Вольфрам. 2017.

Внешние ссылки [ править ]

Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 8d2d50c2d7b18c16b958ab9185b134a0__1717840620
URL1:https://arc.ask3.ru/arc/aa/8d/a0/8d2d50c2d7b18c16b958ab9185b134a0.html
Заголовок, (Title) документа по адресу, URL1:
Homoiconicity - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)