В каком смысле такие языки, как Эликсир и Джулия, гомоиконны?

Гомоиконность в Лиспе легко увидеть:

(+ 1 2)

является как вызовом функции для + с 1, 2 в качестве аргументов, так и списком, содержащим +, 1 и 2. Это одновременно и код, и данные.

Однако на таком языке, как Джулия:

1 + 2

Я знаю, что мы можем разобрать это на Expr в Julia:

:(1 + 2)

А затем мы можем получить AST и манипулировать им:

julia> Meta.show_sexpr(:(1+2)) (:call, :+, 1, 2)

Итак, мы можем управлять AST программы в Julia (и Elixir). Но являются ли они гомоиконными в том же смысле, что и Лисп - это любой фрагмент кода, действительно ли это просто структура данных на самом языке?

Я не понимаю, как код типа 1 + 2 в Julia сразу становится данными - подобно тому, как (+ 1 2) в Lisp - это просто список. Значит, он все еще гомиконичен?


person user2666425    schedule 30.07.2015    source источник
comment
Возможно, вам будет интересно узнать, что Джулия больше не утверждает, что это гомиконно. Основная причина в том, что это плохо определено, поэтому заявление о том, что это так, вызвало гнев некоторых пуристов. Вы не найдете этого слова в документации или на веб-сайте.   -  person IainDunning    schedule 31.07.2015
comment
@IainDunning Действительно интересно - может быть, тогда можно с уверенностью сказать, что такие языки, как Julia и Elixir, поддерживают метапрограммирование и макросы, но не в силу гомоиконности.   -  person user2666425    schedule 31.07.2015
comment
Да, я думаю, это была логика для его удаления. Джулия, возможно, не гомиконична, но вы можете делать большинство вещей, которые ассоциируются с этой идеей (я думаю об этом неформально, как о встроенной относительно простой в использовании возможности написания кода для управления кодом).   -  person IainDunning    schedule 31.07.2015


Ответы (1)


По словам Билла Клинтона, «это зависит от значения слова« есть »». Ну да ладно, не совсем, но это зависит от значения слова «гомоиконный». Этот термин достаточно противоречивый, поэтому мы больше не говорим, что Джулия гомиконична, поэтому вы можете сами решить, подходит ли он. Вместо того, чтобы пытаться определить гомоаконичность, я процитирую то, что Кент Питман (кто кое-что знает о Лиспе) сказано в Интервью со Slashdot в 2001 году:

Мне нравится готовность Lisp представлять себя. Люди часто объясняют это его способностью представлять себя, но я думаю, что это неправильно. Большинство языков способны представлять себя, но у них просто нет желания. Программы на Лиспе представлены списками, и программисты это знают. Неважно, если бы это были массивы. Важно то, что представлена ​​структура программы, а не синтаксис символов, но помимо этого выбор довольно произвольный. Не важно, чтобы это представление было правильным® выбором. Просто важно, чтобы это был общий, согласованный выбор, чтобы могло появиться богатое сообщество программ, управляющих программами, которые «торгуют» в этом общем представлении.

Он также не определяет гомоиконность - он, вероятно, не хочет вдаваться в аргумент об определении больше, чем я. Но он затрагивает самую суть вопроса: насколько язык готов сам себя представлять? Lisp готов в высшей степени - вы даже не можете этого избежать: представление программы в виде данных просто сидит прямо здесь, глядя вам в глаза. Джулия не использует синтаксис S-выражений, поэтому представление кода в виде данных менее очевидно, но не очень глубоко:

julia> ex = :(2a + b + 1)
:(2a + b + 1)

julia> dump(ex)
Expr
  head: Symbol call
  args: Array(Any,(4,))
    1: Symbol +
    2: Expr
      head: Symbol call
      args: Array(Any,(3,))
        1: Symbol *
        2: Int64 2
        3: Symbol a
      typ: Any
    3: Symbol b
    4: Int64 1
  typ: Any

julia> Meta.show_sexpr(ex)
(:call, :+, (:call, :*, 2, :a), :b, 1)

julia> ex.args[3]
:b

julia> ex.args[3] = :(3b)
:(3b)

julia> ex
:(2a + 3b + 1)

Код Джулии представлен типом Expr (а также символами и атомами), и хотя соответствие между синтаксисом поверхности и структурой не так очевидно, оно все еще существует. И что еще более важно, люди знают, что код - это просто данные, которые можно сгенерировать и которыми можно манипулировать, поэтому существует «богатое сообщество программ, управляющих программами», как выразился KMP.

Это не просто поверхностное представление кода Julia как структуры данных - это то, как Julia представляет свой код самой себе. Когда вы вводите выражение в REPL, оно разбирается на Expr объектов. Эти Expr объекты затем передаются в eval, который «понижает» их до несколько более обычных Expr объектов, которые затем передаются в вывод типа, все реализовано в Юлии. Ключевым моментом является то, что компилятор использует то же самое представление кода, которое вы видите. В Лиспе ситуация не такая уж иная. Когда вы смотрите на код Lisp, вы на самом деле не видите объектов списка - они существуют только в памяти компьютера. Вы видите текстовое представление литералов списков, которые интерпретатор Лиспа разбирает и превращает в объекты списков, которые затем оценивает, как и Джулия. Синтаксис Джулии можно рассматривать как текстовое представление Expr литералов - Expr просто оказывается несколько менее общей структурой данных, чем список.

Я не знаю подробностей, но подозреваю, что Elixir похож - может быть, Хосе вмешается.

Обновление (2019 г.)

Подумав об этом больше в течение последних 4+ лет, я думаю, что ключевое различие между Lisp и Julia заключается в следующем:

  • В Лиспе синтаксис кода такой же, как синтаксис структуры данных, которая используется для представления этого кода.
  • В Julia синтаксис кода сильно отличается от синтаксиса структуры данных, представляющей этот код.

Почему это важно? Сторонники Юлии любят особый синтаксис для вещей и часто находят синтаксис S-выражений неудобным или неприятным. На стороне pro-Lisp гораздо проще понять, как правильно выполнять метапрограммирование, когда синтаксис структуры данных, которую вы пытаетесь сгенерировать (для представления кода), совпадает с синтаксисом кода, который вы обычно пишете . Вот почему один из лучших советов, когда люди пытаются писать макросы на Julia, - это сделать следующее:

  1. Напишите пример кода, который должен генерировать ваш макрос.
  2. Вызовите Meta.@dump этого кода, чтобы увидеть его как структуру данных.
  3. Напишите код для создания этой структуры данных - это ваш макрос.

В Lisp вам не нужно делать шаг 2, потому что синтаксис кода уже такой же, как синтаксис структуры данных. В Julia есть квазицитатные (на языке Lisp) конструкции quote ... end и :(...), которые позволяют создавать структуры данных с использованием синтаксиса кода, но это все еще не так просто, как если бы они изначально использовали тот же синтаксис.

См. также:

person StefanKarpinski    schedule 30.07.2015
comment
Таким образом, это скорее PEPL, а не REPL. Поскольку он не читает выражения данных (как это делает Lisp), а анализирует программные выражения в специализированные данные типа expr. - person Rainer Joswig; 31.07.2015
comment
Я не уверен, что в этом разница - S-выражения, несмотря на их минимальный синтаксис, все же нуждаются в синтаксическом анализе, поэтому Lisp REPL на самом деле тоже является PEPL. Я думаю, что основное отличие состоит в том, что тип Expr не является общим, а предназначен только для представления кода. - person StefanKarpinski; 31.07.2015
comment
Разница в том, что синтаксический анализ языка программирования в Lisp не выполняется в READ при вводе текста, но немного отличается в EVAL для структур данных Lisp. EVAL может не преобразовывать данные Лиспа в структуру данных выражения - оценщики могут быть реализованы без этого шага. - person Rainer Joswig; 31.07.2015
comment
Спасибо за отличный ответ. - person user2666425; 31.07.2015
comment
@RainerJoswig, я не слежу за вами - списки - это структура данных выражения Lisp. - person StefanKarpinski; 01.08.2015
comment
Списки - это просто списки. Нет никакого кодирования того, что такое arg, что такое данные, что такое определение, что такое вызов, что такое привязка, что такое функция и т. Д. Списки Lisp ничего не знают о синтаксисе Lisp. READ читает любые данные в формате s-выражения и не имеет нулевых знаний о синтаксисе Lisp. - person Rainer Joswig; 01.08.2015
comment
@RainerJoswig это просто абстракция, а как насчет этого? julia> using LispREPL, набрав ), вы получите lisp> приглашение для Джулии, где вы можете ввести s-выражения! lisp> (for (i (range 1 10)) (print i)), отпечатки: 12345678910, lisp> (show '(+ 2 3)) отпечатки: Any[:+,2,3] и lisp> (typeof '(+ 2 3)) отпечатки Array{Any,1}. github.com/swadey/LispREPL.jl: D - person HarmonicaMuse; 13.01.2016
comment
Я бы сказал, что если Джулия гомиконична, все остальные языки программирования также гомоиконичны, если они предоставляют такие конструкции, как dump и Meta.show_sexpr. - person Wong Jia Hau; 14.02.2019
comment
@WongJiaHau Я думаю, Джулия занимает нишу между такими языками, как C, где макрос - это конкатенация строк и регулярное выражение, и Lisp, выставляя промежуточное (правильно гомоиконное) представление, которым вы можете манипулировать (что также было первой стратегией LISP, если я правильно помню) . Как энтузиаст Лиспа, я не особо в этом разбираюсь, но мне действительно нравится честность автора и их попытка предоставить что-то в духе метапрограммирования. Аааанннд .... только сейчас замечаю, что коментариям 5 лет ...: D - person Rick77; 08.11.2019