Действительно ли гомоиконичность необходима для того, чтобы иметь макросы?



2012-02-04 спонсируется словом "гомоиконичность" http://en.wikipedia.org/wiki/Homoiconicity .



Предыстория: Я собираюсь выбрать, какую книгу о Clojure купить - либо "Clojure in Action", либо (поступление в конце апреля) "Программирование Clojure" (вы можете прочитать ее через O'Reilly Rough Cuts, половина страниц видна). Что меня поразило, так это то, что в обеих книгах этому свойству-гомоиконичности-придавалось такое большое значение.



С тех пор Корни Clojure основаны на Лиспе, я упомянул "dead sexy" книгу это действительно так важно. Ну, я вижу макросы, объясненные подробно, но я не уловил упомянутого акцента. Теперь сравните с этим (цитата из "Clojure in Action")




Это гомоиконичность также то, что делает система в Clojure макрос можно.




Похоже, что без него макросы были бы невозможны. Даже заявление Википедии (ссылка выше) более сбалансировано, но ни один из этих источников (*) считает человеческий фактор в пользу английского синтаксиса.



Если я не ошибаюсь, синтаксис макросов (Лисп-подобный) может быть возможен в C# (например), только с большим усилием со стороны команды C#. Но это стоимость команды дизайнеров, а не пользователей (?). Второе-дело привычки. Если в реальной жизни вы думаете "a + b", а в компьютерном мире постоянно переводите его на" + A b", производительность страдает (я сам это вижу, когда перешел от функторов C++ к лямбдам C#).



Эта похвала, что Клоджур программист пишет программы почти напрямую, как АСТ, пугает меня, как чтение, что "благодаря написанию кода непосредственно в шестнадцатеричном коде, вы не только учите шестнадцатеричную систему наизусть, но вы ближе к машине".



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

Вопрос



Действительно ли гомоиконичность так полезна для людей (конечных пользователей языка) или она на самом деле почти исключительно полезна для разработчиков языка? Примеры очень приветствуются!



Или просто в случае, если я перефразирую -- предполагая, что данный язык имеет Lisp-макросы," добавление " гомоиконичности повысит производительность конечного пользователя? Выразительность? Или совсем наоборот?



(*) я не могу быть уверен на 100%, потому что вижу только часть книг Клоджюра, и я не читаю их, а просто оцениваю их для покупки.



Обновление



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

669   5  

5 ответов:

Гомоиконичность не является строго обязательным для макросов (например, на C/C++ препроцессор реализует компиляции макроса системного времени).

Однако гомойконсити делает макросы намного более эффективными и простыми в использовании:

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

В качестве небольшого примера, вот макрос, который добавляет цикл Java / C# style " for " в Clojure.

(defmacro for-loop [[sym init check change :as params] & steps]
 `(loop [~sym ~init value# nil]
    (if ~check
      (let [new-value# (do ~@steps)]
        (recur ~change new-value#))
      value#)))

;; Usage:
(for-loop [i 0 (< i 10) (inc i)] 
  (println i))

И это все - новая языковая конструкция, добавленная в шесть строк кода. Вы можете ясно видеть гомоиконичность в действии-вся форма "цикла" является просто цитируемой структурой данных Clojure. Метод init, проверять и менять параметры также homoiconic структуры данных Clojure передается в макрос, которые представляют собой контур регулирования выражений. Не было никакой необходимости делать какой-либо синтаксический анализ, чтобы поддержать мой новый синтаксис.

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

Нет, вам не обязательно нужна гомоиконичность, чтобы создать мощную, похожую на Лисп макросистему. Гомоиконичность просто делает такую систему намного проще в использовании; без нее вам понадобился бы другой синтаксис для выражения AST, которые макросы производят при вычислении. В гомойконическом языке макросистема кажется естественной, поскольку программы и метапрограммы выглядят одинаково.

Гомоиконичность-это плохо определенное понятие.

Что отличает Lisp, так это то, что он имеет представление данных исходного кода, и вычислитель принимает его в качестве входных данных. Обработка исходного кода в виде данных проста, так как применяется вся обычная функциональность Lisp.

Что это дает:

  • чтение текстового источника и создание из него структур данных
  • обработка источника Как данных
  • печать "источника Как данных" в виде текста, включая такие вещи, как pretty печать кода
Макросы-это функции, преобразующие исходный код. Таким образом, все, что вам нужно, - это некоторое представление исходного кода и шаг в выполнении/компиляции/интерпретации языка программирования, где происходит этот шаг преобразования.

Способ работы Lisp делает его удобным, так как исходный код - это структура данных, которой можно манипулировать с помощью множества встроенных функций и средств. Заметим, что более сложные преобразования, где нужно чтобы понять синтаксис языка Lisp, также нелегко сделать в Lisp-хотя инструменты были реализованы (например, так называемые ходунки кода).

Существуют также Лиспы, синтаксис которых не основан на s-выражениях. Примером может служить RLISP, язык реализации системы компьютерной алгебры REDUCE. RLISP также поддерживает макросы.

Можно было бы определить аналогичную схему, основанную на строках и манипуляциях со строками. Вы также можете определить макрос система, основанная на каком-то АСТ.

Пример языков с такими макросами:

  1. Дилан. Смотрите: http://opendylan.org/books/dpg/macros.html
  2. Джулия. Смотрите: https://en.wikipedia.org/wiki/Julia_ (programming_language)
  3. Немер. Смотрите: https://github.com/rsdn/nemerle/wiki/Macros-tutorial

Представьте, что вы используете старую и неудобную методологию языка веб-шаблонов <% code %> для использования встроенной java в python.

Тогда макроязык будет java, а целевой язык-python. Вызов макроса будет означать выход в режим <% code %>. Вы даже можете создать такую систему для поддержки параметров, оценки строк и т. д. Это было бы действительно некрасиво (вроде старого кода jsp или php).

Страшная мысль: могут ли некоторые пользователи jsp найти такую систему больше удобнее, чем система lisp? Был бы этот монстр улучшен, если бы макро/целевой язык был таким же?

Так что, конечно, это можно было сделать. Люди сделали некоторые удивительные вещи с шаблонами C++. Джей Фримен написал программу на C++ с Ackermann compile time и constant run time, чтобы продемонстрировать, что шаблоны C++ могут делать такие вещи (предположительно, потому что примеры Фибоначчи не взрывают достаточное количество компиляторов?).

Как для гомоиконичность: это не решит всех проблем. Даже с ним, там часто бывает какая-то неловкость: кавычки, квазикавычки и т. д. Вам нужен какой-то способ переключения между "Это макрокод" и "это код целевого языка". Это неотъемлемая проблема, которую должны решать языковые дизайнеры. Вместо шепелявого языка со списками в качестве структур данных или программного кода, Вы могли бы думать только о неприятностях использования строк с методом eval. Исходный код программы - это что-то вроде строки. Строка-это действительно ужасная структура данных. А струны внутри струн ровны хуже. Найдите любой код Куайна (peferably non-lisp). Их можно рассматривать как гомоиконичность, совершенную ужасно неправильно.

Хотя вам нужен язык для макросов, он не обязательно должен быть тем же языком, на котором написан остальной код. все, что вам нужно, - это "iconicity"*, часть "homo" необязательна.

В Ocaml макросы записываются на другом языке, называемом camlp4

Это выглядит примерно так:

#load "pa_extend.cmo";

value gram = Grammar.gcreate (Plexer.gmake ());
value exp = Grammar.Entry.create gram "expression";

EXTEND
  exp:
  [ "SUM"
    [ x = exp; "+"; y = exp -> Op "+" x y
     | x = exp; "-"; y = exp -> Op "-" x y]
  | "PROD"
    [ x = exp; "*"; y = exp -> Op "*" x y
    | x = exp; "/"; y = exp -> Op "/" x y]
  | "ATOM"
    [ x = INT -> Int (int_of_string x)
    | x = LIDENT -> Var x
    | "("; x = exp; ")" -> x ] ]
  ;
END;

Где язык, который он преобразует, выглядит следующим образом:

let rec search ?(x=0) ?(y=0) f accu = match x, y with
    9, y -> search ~x:0 ~y:(y+1) f accu (* Next row *)
  | 0, 9 -> f accu                      (* Found a solution *)
  | x, y ->
      if m.(y).[x] <> '0' then search ~x:(x+1) ~y f accu else
        fold (fun accu n ->
                let n = Char.chr (n + 48) in
                if invalid x y n then accu else
                  (m.(y).[x] <- n;
                   let accu = search ~x:(x+1) ~y f accu in
                   m.(y).[x] <- '0';
                   accu)) accu 1 10

Как вы можете видеть, в Ocaml нет гомоконичности, и он имеет высокоразвитая макро (подобная) система.

  • это не настоящий термин, я придумал его в надежде, что кто-то улыбнется :)

Comments

    Ничего не найдено.