Рубрики
Без рубрики

Концепция дня: Гомоиконичность

фото sum+it от Pexels Слово homoiconic можно понять, изучив его корни: homo, m… С тегами lisp, java, javascript, todayilearned.

фото автора сумма+это от Пиксели

Слово гомоиконическое можно понять, изучив его корни: homo , что означает “то же самое”, и icon , что означает “представление”. Согласно Wikipedia , язык является гомоиконическим, “если программой, написанной на нем, можно манипулировать как данными, используя язык, и, таким образом, внутреннее представление программы может быть выведено просто путем чтения самой программы”.

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

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

Это строгое определение по существу исключает гомоиконичность любого языка программирования, поскольку даже текстовое представление двоичного кода все равно отличается от самого двоичного кода.

Соответственно, даже такие языки, как LISP, которые претендуют на то, чтобы быть гомоиконическими , правильнее описывать как para iconic , термин, который предлагается в приведенной выше ссылке. В этих параиконических языках исходный код любой программы сам по себе является исходным кодом для конкретной структуры данных в пределах этого языка, который может быть eval() -uated и обрабатываться как объект в пределах этого языка. Вот откуда взялось общее определение гомоиконичности, “код как данные” .

Одним из способов представить это был бы теоретический язык, полностью написанный на JSON (объектная нотация JavaScript).:

{
  "main" : {
    "type"   : "function",
    "params" : [ "args" : [...] ],
    "body"   : [ ... ],
    ...
  }
}

Если бы этот язык также обладал способностью манипулировать файлами JSON, то он мог бы выполнять любые произвольные изменения в своем собственном исходном коде. Вот почему идея “код как данные” имеет некоторый смысл. Другим (возможно, немного более простым) примером является LISP, где выражение S может описывать целую программу, но само по себе является объектом в языке программирования LISP:

(1 2 3)

Приведенный выше код LISP – и выражение – создают список из трех элементов 1 , 2 , 3 . Строковое представление этого объекта — (1 2 3) — является точно равным коду, необходимому для создания самого объекта. Поскольку LISP может манипулировать S-выражениями, и поскольку все программы LISP полностью написаны на S-выражениях, каждая программа LISP, какой бы сложной она ни была, представляет собой просто список LISP. Каждая программа LISP – это объект, которым можно управлять с помощью языка LISP.

Это не то же самое , что и внутреннее представление программы ( абстрактное синтаксическое дерево, AST ), несмотря на некоторые утверждения в Интернете.

Это неверно для такого языка, как Java, где строковое представление объекта часто отличается от исходного кода, необходимого для создания этого объекта:

jshell> int arr[] = { 1, 2, 3 };
arr ==> int[3] { 1, 2, 3 }

jshell> arr.toString()
$3 ==> "[I@1bce4f0a"

Для того, чтобы воссоздать это на таком языке, как Java, например, нам нужно было бы иметь возможность восстановить, с помощью отражения или иным образом, фактическое имя переменной arr . В настоящее время это невозможно в Java. Кроме того, нам нужно было бы иметь возможность восстановить тип объекта arr , который – благодаря стиранию типа – также недоступен. Все объекты Java относятся к классу Объект во время выполнения.

Пара-иконичность означает, что программы на ЛИСПЕ могут очень легко оценивать, интерпретировать и изменять другие программы на ЛИСПЕ. Поскольку правильно отформатированное S-выражение может быть интерпретировано из его строкового представления, и поскольку все программы LISP являются просто сложными S-выражениями, LISP может легко считывать в программе LISP из внешнего файла и манипулировать им как объектом. ” Код как данные” действительно.

Я надеюсь, что это объяснение пролило некоторый свет на различия между гомоиконичностью и более распространенная пара-иконичность , и то, как некоторые языки включают это свойство , в то время как другие делают его трудным или невозможным.

Оригинал: “https://dev.to/awwsmm/concept-of-the-day-homoiconicity-4did”