В какой области макрос LISP лучше, чем «способность» Руби создавать DSL?

21

Одна из вещей, которая делает Ruby сиять, - это возможность создавать доменные языки лучше, например,

Хотя можно скопировать эти библиотеки в LISP с помощью макроса, я думаю, что реализация Ruby более элегантна. Тем не менее, я думаю, что есть случаи, когда макрос LISP может быть лучше, чем макрос Ruby, хотя я не мог придумать ни одного.

Итак, в какой области макрос LISP лучше, чем «способность» Руби создавать DSL, если таковая имеется?

Обновить

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

  • C получил препроцессор расширения макросов , хотя и очень примитивный и подверженный ошибкам
  • C # имеет атрибуты, хотя это только для чтения, через отражение
  • Python добавил декоратор, который может изменить поведение функции (и класса для v 3.0), хотя и чувствует себя довольно ограниченным.
  • Ruby TMTOWTDI, который делает элегантный DSL, если применяется осторожность, но в Ruby.

Мне было интересно, применим ли макрос LISP только к особым случаям и что другие функции языка программирования достаточно мощны, чтобы поднять абстракцию для решения задач, стоящих сегодня в разработке программного обеспечения.

OnesimusUnbound
источник
4
Я не совсем уверен, почему есть близкие голоса по этому вопросу. Я думаю, что это тот вопрос, который мы хотим ? Интересно, наводит на размышления, и размах определяется довольно хорошо.
Тим Пост
Попробуйте реализовать что-то подобное в Ruby: meta-alternative.net/pfront.pdf
SK-logic
@Tim Post: Одна из проблем заключается в том, что на этот вопрос сложно ответить, если вы не хорошо знаете Common Lisp и Ruby. Другой - довольно невежественные ссылки на другие языки, которые могут раздражать пуристов: нет языка с именем C / C ++, и значительная часть C ++ является системой шаблонов, и предположение, что макросистема Common Lisp применима только к особым случаям. По сути, это хороший вопрос, но он написан плохо и на него сложно ответить.
Дэвид Торнли
@David Thornley, я обновил пост, особенно на C \ C ++, и сделал упор на C. Что касается Common Lisp, я чувствовал, что, поскольку другие языки программирования имеют более высокую абстракцию, эта функция макроса предназначена для особого случая. Я опубликовал вопрос, надеясь, что другие покажут мне, что макрос CL не для особых случаев - все еще мощная функция.
OnesimusUnbound
@OnesimusUnbound: я бы действительно включил шаблоны C ++ в ваш список примеров языка, поскольку они, по крайней мере, теоретически способны на любые вычисления, которые может выполнять макросистема Lisp. Что касается макросов Lisp, то получите хороший Common Common Lisp-код (в нем много кода для F / OS Lisp) и выполните поиск «defmacro» (возможно, вы захотите выполнить поиск без учета регистра). Вы, вероятно, найдете их много. Учтите, что макросы сложнее, чем функции, чтобы писать и понимать правильно, и вы поймете, что они должны быть в целом полезны.
Дэвид Торнли

Ответы:

23

Читайте на Лиспе и решайте сами.

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

btilly
источник
1
«Let Over Lambda» охватывает много похожих мест. Также рекомендуется к прочтению.
Джон Р. Штром,
But Lisp wins, hands down, at the ability to create new abstractions, and then to layer abstraction on abstraction.Теперь я знаю почему. , ,
OnesimusUnbound
Нет ничего сложного в том, чтобы предоставить какой-либо синтаксис поверх Lisp. На самом деле, намного проще, чем с Ruby, благодаря читателю макросов.
SK-logic
1
@ SK-логика: правда. Однако Лисперс уклоняется от макросов читателя, потому что когда вы идете по этому маршруту, он больше не ощущается как Лисп. Фактически некоторые варианты Lisp, такие как Clojure, резервируют макросы читателя для дизайнера языка.
Btilly
14

Возможности Ruby для создания DSL не меняют природу языка. Средства метапрограммирования Ruby неразрывно связаны с синтаксисом и семантикой Ruby, и все, что вы пишете, должно быть добавлено в объектную модель Ruby.

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

По сути, Ruby DSL все еще ощущается как Ruby, но Lisp DSL не должен чувствовать себя как Lisp.

Джон Перди
источник
6
+1: LOOP не чувствует себя очень плохо, как пример DSL.
Фрэнк Ширар
2

DSL в Ruby вовсе не являются DSL, и я совершенно не люблю их использовать, потому что их документация прямо показывает, как они действительно работают. Давайте возьмем ActiveRecord для примера. Это позволяет вам «объявлять» ассоциации между моделями:

class Foo < ActiveRecord::Base
    has_one :bar
    has_one :baz
end

Но декларативность этого «DSL» (как и декларативность самого classсинтаксиса Ruby ) - ужасная ложь, которую может разоблачить любой, кто понимает, как на самом деле работают «DSL» в Ruby:

class Foo < ActiveRecord::Base
    [:bar,:baz,:qux,:quux].each do |table|
        has_one table if i_feel_like_it?(table)
    end
    puts "Just for shits and giggles, and to show"
    puts "just how fucked up Ruby really is, we're gonna ask you"
    puts "which SQL table you want the Foo model to have an"
    puts "association with.\n"
    puts "Type the name of a table here: "
    has_one gets.chomp.to_sym
end

(Просто попробуйте сделать что-нибудь близкое к этому в теле defclassформы Lisp !)

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

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

DSL Lisp реализуются с помощью макросов, которые являются маленькими компиляторами. DSL, которые вы можете создать таким образом, - это не просто нарушение существующего синтаксиса Lisp. Это настоящие мини-языки, которые могут быть написаны как полностью цельные, потому что они могут иметь свою собственную грамматику. Например, LOOPмакрос в Лиспе намного мощнее, чем eachметод Руби .

(Я знаю, что вы уже приняли ответ, но не все, кто его прочтет, захотят прочесть всю версию On Lisp .)

Сбросить аккаунт
источник