Сравнение общих макросов Lisp и возможностей метапрограммирования Forth

Каждый программист Common Lisp знает, что макросы являются мощным инструментом. Общие макросы Lisp были использованы, среди прочего, для добавления ориентации объектов поверх Lisp без изменения спецификации языка; read-macros - это еще одна конструкция с возможностями изгиба ума.

Другая программа, которая позволяет метапрограммировать Forth. Форт делает это несколько иначе, используя "слова" и "генерировать слова".

Я хотел бы знать, от кого-то, кто ругался на обоих языках, если общие макросы и конструкторы Lisp сопоставимы по ширине/мощности: есть ли что-то, что вы можете сделать с тем, что вы не можете сделать с помощью последний? Или наоборот?

Конечно, я не говорю о Turing-полноте двух языков: я говорю о возможностях metaprogramming. C является завершением Тьюринга, но только глупец утверждает, что макросы C сравнимы по мощности с Common Lisp.

Ответ 1

На мой взгляд, общие макросы Lisp похожи на быстрые слова Forth. (На самом деле они наиболее похожи на макросы чтения Lisp.)

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

  • Оба они имеют доступ к исходному коду.

  • Оба они могут выводить все, что выражается на языке. (Например, объектно-ориентированное расширение в Lisp или базовые конструкции потока управления в Forth.)

Основное отличие, возможно, в том, что входные макросы Forth являются символьными строками, а макросы Lisp работают на дереве разбора.

Ответ 2

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

Относительно легко построить абстракции поверх абстракций в LISP. В Forth, если я хочу определить матрицу на линейном пространстве, определенном объектами с нетривиальными определениями.. Я переключаюсь на Python.

Причина также очевидна, по крайней мере, для меня. Создатели LISP, где математики, в то время как Чак Мур - лучший пример практического программиста, никогда не тратят свое время на теоретическую проблему.

Это распространяется на этот вопрос следующим образом. Макрос lisp имеет структуру в контексте Lisp и, по крайней мере, предлагает значение, соответствующее общим принципам lisp. Непосредственное слово Forth - это просто другая программа, которая может означать и делать что угодно, включая приготовление из нее обеда для собак.

Ответ 3

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

У меня есть только теоретические знания Lisp, а не руки.

С другой стороны, Forth мог иметь (но нормальный Forth не) полное метапрограммирование внутри языка. Но метапрограммирование рассматривается и возможно, но без согласованного синтаксиса. Я думаю, что то же самое происходит в Lisp.

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

bread eat

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

{ bread eat } 

Вышеупомянутая фраза может иметь как следствие оставить созданный объект в стеке. Но поскольку мы создали новое слово как { и }, мы также имеем право ссылаться на это.

Итак, мы могли бы сослаться на:

{ bread 

Как мы можем на это ссылаться? Ориентировочный синтаксис: {{ { bread }}.

Если мы приведем название XXX к предыдущей фразе, мы могли бы написать начальную фразу как:

XXX eat }

и фраза выше должна корректно работать, оставляя в стеке

{ bread eat }

Как я не знаю, что именно я говорю, именно то, что вы ищете, достаточно сказать, что по приведенным выше рассуждениям и их реализации внутри Forth каждое слово получает уровень выполнения и определяет, который является уровнем метапрограммирования слова.

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

Я реализовал вышеупомянутое внутри своего рода Forth и на первом уровне (ниже бесконечности) все работает плавно. Так, например, я могу изменить синтаксис:

{ bread eat } { tomatos eat } x 3 = if 

в

{ bread eat | tomatos eat } x 3 = if 

Это делается путем определения | как } { как ниже:

{{ } { }} "|" define

или если вам это нравится лучше:

2{ } { 2} "|" define 

Вышеприведенный метод берет внутри языка с правильным синтаксисом метаязык и делает его языком.

Таким образом, по моему мнению, оба Lisp и Forth имеют возможность метапрограммирования, но обе не имеют такой возможности как интегрирующей части языка.

У меня есть более подробная информация об этом на napl.wikispaces.com.