swizard опубликовал статью о Common Lisp и DSL, в которой достаточно ясно изложил мнение, что наиболее эффективное использование Common Lisp заключается в разработке DSL. Мало того, он предлагает начинающим начинать именно с этого. Позвольте не согласится.
Кратко - DSL не нужны кроме тех редких случаев, когда они очень хороши и реально упрощают решение задачи. Это не имеет отношения к Common Lisp, либо к какому либо другому языку. Например, Эрик Раймонд писал о DSL как о классической традиции программирования под UNIX и всяческих расхваливал преимущества данного подхода. Однако на практике лишь малая часть Unix-программ используют какие-либо DSL. Это однозначно свидетельствует о том, что разработчики, несмотря на все разрекламированные свойства DSL, стараются избегать их использования (да, я действительно считаю, что "миллионы мух не могут ошибаться", поскольку речь идёт не о мухах, а о, по большей части, талантливых разработчиках).
Если говорить о Common Lisp, то мне совершенно не понятно на чём основано мнение, что "common lisp и заслужил себе славу мета-языка " (с). В реальной практике программирования на Common Lisp использование DSL встречается редко. Связано это с тем, что, на мой взгляд, использование DSL просто противоречит духу Common Lisp, по крайней мере, в его современном виде.
Наиболее сильной и характерной чертой Common Lisp является мощная поддержка интерактивной разработки, что значительно упрощает постоянный рефакторинг кода и проектирование "снизу вверх", которые характерны для современных подходов к разработке. Программирования на основе DSL, однако, требует другого подхода: задача делится на две подзадачи - проектирование DSL и описание решения на этом DSL. Проектирования языка программирования, пусть даже это маленький DSL, это сложная задача, повышающая требования к качеству проектирования системы. В контексте современных задач, когда приложение работает сразу во многих областях, также существенно усложняется выделения предметной области для конкретного DSL. Сложность возникающих проблем дизайна приводит к необходимости проектирования "сверху вниз", что стразу убивает большую часть преимуществ интерактивной разработки. Поскольку для современных задач характерна неточность в требованиях, которые выясняются по мере разработки (обычно, ближе к концу), то проектирование "сверху вниз" связано со слишком большими рисками и сопутствующими накладными расходами.
Использование DSL возможно и целесообразно лишь в некоторых областях, но не для широкого круга задач. ИМХО, мнение о том, что при программировании на Common Lisp следует широко использовать DSL основано на позиции старой "lisp-гвардии", представители которой застряли где-то в начале 80-ых.
Подписаться на:
Комментарии к сообщению (Atom)
Надо заметить, что грань между Embedded DSL и хорошим API довольно тонка, и тем она тоньше, чем язык экспрессивнее, поэтому я скорее соглашусь со swizard'ом.
ОтветитьУдалить> Однако на практике лишь малая часть Unix-программ используют какие-либо DSL.
Интерпретаторы shell — яркий пример DSL, далее регулярные выражения, конфигурация iptables и т.п.
> Связано это с тем, что, на мой взгляд, использование DSL просто противоречит духу Common Lisp, по крайней мере, в его современном виде.
Вот на это, хотелось бы услышать более развёрнутый ответ.
@bsdemon
ОтветитьУдалитьНет, граница между API и eDSL достаточно чёткая, ибо DSL предполагает стадию стадию трансляции кода.
> Интерпретаторы shell — яркий пример DSL
Нет, ибо тот же bash и т.п. это достаточно полноценные языки программирования, без чётко выделенной предметной области.
> Вот на это, хотелось бы услышать более развёрнутый ответ.
Там только углублять тезисы. Чем отличаются различные подходы к проектированию. Почему я предпочитаю "снизу вверх" и т.д.
Я тоже со swizard'ом не согласился по философии статьи. Он во введении говорит, что научный метод познания (использование старого опыта там, где возможно) - на голову ошибочное.
ОтветитьУдалитьЛисп - он вообще хорош тем, что начинать изучать его можно с любой стороны.
> Нет, граница между API и eDSL достаточно чёткая, ибо DSL предполагает стадию стадию трансляции кода.
ОтветитьУдалитьНу если API представляется макросом, то этот макрос как раз и есть - стадия трансляции кода (макрос делает преобразование sexp -> sexp (aka AST)).
Если брать примеры каких-нибудь простых макросов:
1) макросы with-* имеют в качестве domain цели автоматическое конструирование/де-конструирование объектов.
2) анафорические макросы имеют в качестве domain автоматическое связывание переменных в окружении.
3) ещё - описание системы в ASDF это DSL или нет?
4) Макросы подобные defsystem в ASDF, которые написаны в соответствии с некоторыми правилами (синтаксис этого DSL) и определяют (генерируют, или транслируют), скажем, классы и методы. Это DSL?
@quasimoto
ОтветитьУдалить> Ну если API представляется макросом, то этот
> макрос как раз и есть - стадия трансляции кода
Нет, макрос не определяет нового языка. Макросы сами по себе не определяют DSL и никакого отношения к DSL не имеют. Макросы и DSL ортогональны.
> описание системы в ASDF это DSL или нет?
Нет. ASDF это всего лишь формат данных.
Весь смысл использования DSL в CL в том, что DSL не является инородной конструкцией языка, а вплетён в язык с помощью макросов. Таким образом, получается очень легко использовать CL из DSL и наоборот. На мой взгляд, в этом суть использования метапрограммрования и DSL в лиспе. А проектировать DSL "сверху вниз" вроде никто и не предлагает. Всегда лучше обойтись стандартными конструкциями лиспа, и использовать DSL для того, для чего он действительно нужен.
ОтветитьУдалить@Valeriy Fedotov
ОтветитьУдалитьНикакой связи между метапрограммированием и DSL нет, это совершенно разные понятия. Кроме того, что такое метапрограммирование в CL вообще плохо понятно, этот термин больше подходит для использования в языках со статической типизацией.
> Макросы и DSL ортогональны.
ОтветитьУдалитьТ.е. когда я ввожу себе DSL с помощью двух-трёх макросов, то я... не ввожу себе DSL?) Мне всё-таки кажется что если я придумал себе DSL и реализовал его "на макросах" то иначе как "использованием макросов для реализации DSL" это не назвать. Следовательно макросы это (в том числе) средство построения DSL-ей. Кстати, в той статье утверждается что конструкции вроде define-vop в SBCL это DSL, ну так это DSL на макросах.
> ASDF это всего лишь формат данных.
Ну так всё формат данных :) (код - тоже данные, скажем). Очень общая характеристика "формат данных".
Я бы сказал так:
1) Если принять типичное определение DSL (как в википедии, например), то некий декларативный формат данных с определённым синтаксисом, который однозначно определяет какие-то вычислители - это DSL. В этом смысле любой более-менее сложный макрос вводит DSL по отношению к своим входным SEXP-ам (и в этом смысле язык defsystem это DSL и define-vop - тоже).
2) Акцентировать внимание на L (Language) и требовать полноту этого языка - неправильно. Требование полноты как раз определяет common domain language (CDL), а DSL это как раз декларативный (обычно) язык который : -*- имеет определённый синтаксис (набор синтаксических правил), -*- и имеет набор правил трансляции DSL -> CDL.
> Т.е. когда я ввожу себе DSL
ОтветитьУдалитьПонятия макросов и DSL ортогональны. Ты можешь использовать макросы при определении eDSL, а можешь и не использовать. Связи между макросами и DSL нет.
> конструкции вроде define-vop в SBCL это DSL,
И?
> формат данных с определённым синтаксисом,
> который однозначно определяет какие-то
> вычислители - это DSL
mp3 это DSL? И HTML тоже DSL? Для примера - PostScript - это DSL, а PDF, хотя и основан на PostScript, - формат.
> и требовать полноту этого языка
Никто её не требует. Понятие Тьюринг-полноты ортогонально понятию DSL.
Вообще, вынужден отослать к изестному труду Э.Раймонда (Исскустно программирования для Unix). Там теме DSL посвящена одтельная глава. И там есть примеры типичных DSL. В своём понимании что такое DSL я ориентируюсь на них.
Иначе всё что угодно можно объявить как DSL, а в этом случае весь смысл понятия утрачивается.
@quasimoto
ОтветитьУдалитьКстати, в википедии на редкость тупая статья
> И?
ОтветитьУдалитьНу да, DSL на макросах, ок.
> Ты можешь использовать макросы при определении eDSL, а можешь и не использовать. Связи между макросами и DSL нет.
Ну с этим я не спорю - конечно, макросы это средство (и для DSL и для метапрограммирования). Тем не менее вот ты писал:
> Если говорить о Common Lisp, то мне совершенно не понятно на чём основано мнение, что "common lisp и заслужил себе славу мета-языка " (с).
Метапрограммирование это в первую очередь кодогенерация с использованием макросов - то как связаны между собой стадии macroexpand/eval/compile - это и есть "слава мета языка". Благодаря этой связи то что в языках без метапрограммирования было бы надстроенным интерпретатором в CL может быть компилятором (и тут вопрос - компилятором чего во что? ответ - DSL в CL примитивы, вот тут как раз и видна связь DSL и метапрограммирования (кодогенерации)).
> mp3 это DSL? И HTML тоже DSL? Для примера - PostScript - это DSL, а PDF, хотя и основан на PostScript, - формат.
Я написал что такое DSL в предыдущем посте. mp3 это не DSL так как mp3 это не язык (под L подразумевают формальный язык, у которого есть чёткое определение). DSL это во-первых язык (заданный любой грамматикой) который не полон (поэтому specific, точнее - его полнота вообще нас не интересует (поэтому он декларативен)) и во-вторых правила трансляции этого языка в (другой) полный язык (CDL). Т.е. говорить что язык HTML это DSL имеет смысл только в том случае, если добавить определённые правила трансляции (например отрисовка этого HTML). То же самое касается XML - так это просто декларативный язык, в добавлении определённых правил трансляции это уже DSL того или иного назначения (есть любители строить DSL на XML :) типа "программа управления роботом").
> Иначе всё что угодно можно объявить как DSL, а в этом случае весь смысл понятия утрачивается.
Формально, определение такое: DSL = (Lang, Trans (Lang -> CDM)), чем бы ни был Lang.
> Метапрограммирование это в первую очередь
ОтветитьУдалить> кодогенерация с использованием макросов
Сфига? У каждого языка будет своё определения метапрограммирования? Что будем делать с метапрограммированием в C++ или том же Haskell?
> Формально, определение такое: DSL =
> (Lang, Trans (Lang -> CDM)), чем бы ни был Lang.
Это ещё сфига?
> Сфига? У каждого языка будет своё определения метапрограммирования? Что будем делать с метапрограммированием в C++ или том же Haskell?
ОтветитьУдалитьДа, в CL эти "макросы" известны как macros (как и в Nemerle), в Haskell реализуются с помощью TH, в F#, OCaml (camlp) и C++ (templates) они имеют более ограниченные возможности - но принцип везде один и тот же.
> Это ещё сфига?
Ну так по науке - такое определение )
> они имеют более ограниченные возможности
ОтветитьУдалитьСфига это ещё?
> Ну так по науке - такое определение )
Ты их сам изобретаешь?
>> они имеют более ограниченные возможности
ОтветитьУдалить> Сфига это ещё?
C++ templates vs. CL macros - ? В первом нет возможности преобразования произвольного кода, например (фактически там главное-то - диспетчеризация по классу).
> Ты их сам изобретаешь?
Сфига мне самому их изобретать? ;D Так принято выражаться о языках в теории формальных языков. То есть этой записью мы утверждаем, что
1) Есть язык Lang, заданный произвольной грамматикой. Чаще всего простой грамматикой - возможно даже что язык конечен.
2) Есть язык CDL, для которого доказана его Тьюринг-полнота.
3) Полнота языка Lang нас не интересует, так как:
4) Есть отображение Lang -> CDL (трансляция).
В этом случае Lang это DSL. Естесвенно такой формализм очень обтекаем - на практике нужно определять что это за domain, но если это сделано, то любой DSL попадает под такое определение.
К примеру:
1) Мы берём язык s-выражений,
2) И полный язык (вычислитель) CL
3) определяем над s-выражениями какие-то семантические правила (как в defsystem или define-vop).
4) определяем макрос который проводит трансляцию:
(s-выражение, набор наших семантических правил) -> код на CL (например, определение класса и ряда его методов).
Язык s-выражений (которому изоморфен HTML или XML) это НЕ DSL - ты это наверно имеешь ввиду. Но пара (s-выражение, набор наших семантических правил) это и есть DSL, по определению.
(выражение, набор наших семантических правил)
ОтветитьУдалить^
это, кстати, Кнут придумал - вообще применительно к любой трансляции языков. Lang является DSL при неких дополнительных условиях (потому specific).
> C++ templates vs. CL macros - ?
ОтветитьУдалитьДавай начнём с того, что язык шаблонов С++ является Тьюринг-полным, на нём даже интепретатор лиспа (времени компиляции) реализовали...
> Естесвенно такой формализм
Перестань курить абстракции в таких дозах. DSL это термин из инженерной практики проектирования. Никакие надуманные формализмы здесь не при чём.
> Давай начнём с того, что язык шаблонов С++ является Тьюринг-полным, на нём даже интепретатор лиспа (времени компиляции) реализовали...
ОтветитьУдалитьЯ уже читал это на ЛОРе :) Я сказал только "нет возможности преобразования произвольного кода" - то факт.
> DSL это термин из инженерной практики проектирования.
Ну, может я и правда перегибаю с абстракциями. Для меня это просто способ подвести общую основу под метапрограммированием и DSL в разных языках (вот мы определили - и больше можно не путаться).
По крайней мере ты согласился, что выражения в define-vop (вместе с правилами их трансляции в CL код) это DSL. Но почему выражения в defsystem (тоже - вместе с правилами генерации кода макросом) - нет?
Я вот думаю что код в defsysem в *.asd это Domain Specific Language domain которого это System Definition Facility (который ещё another) ;)
ОтветитьУдалить@quasimoto
ОтветитьУдалитьЯ недостаточно знаком с внутренним устройством SBCL, что бы судить обоснованно, но вполне допускаю, что define-vop действительно связано с DSL.
А ASDF не определяет никакого языка, на котором можно программировать. ASDF ни в коем случае не может считаться DSL. При желании, ASDF можно рассматривать как data driven систему, но не более.
> А ASDF не определяет никакого языка, на котором можно программировать.
ОтветитьУдалитьЯзык это просто произвольное множество наборов значков. Т.е. {a, b, aa, bb} - язык в котором можно сказать a или a или aa или bb, а его словарь - {a, b}.
Я к тому, что называют "языком". Он может быть декларативным - т.е. ничего особо не по-программируешь, просто можно декларативно что-то определить. Как в ASDF - вот есть такая-то система. Суть в том что описания этого декларативного языка транслируются в выполняемый код (макросом) - этим и осуществляется "программирование" (в ASDF - задание системы).
> Язык это просто произвольное множество наборов значков.
ОтветитьУдалитьОпять неуместная абстракция.
DSL - это такой специальный язык программирования. ASDF языком программирования не является.
Как мне показалось, у вас представление о DSL как о *языке программирования*, который обязательно должен этап интерпретации или трансляции в хост язык. Общепризнанное определение DSL[1] говорит, что это язык программирования или спецификация, которые потом транслируются в хост язык с помощью интерпретатора/компилятора (external DSL) или кодогенерации (internal DSL). Как раз например, язык описания в ASDF и является спецификацией, поэтому его можно считать DSL. Хотя конечно понятие DSL расплывчато, и даже фаулер пишет об этом в своей книге[2], что разница между API и DSL не так уж ясна, однако, чтобы не подразумевалось под этим термином, главное, чтобы это помогало решить задачу. В этом я с ним полностью согласен.
ОтветитьУдалить[1] > A domain-specific language (DSL) is a programming language or executable specification language that offers, through appropriate notations and abstractions, expressive power focused on, and usually restricted to, a particular problem domain. ( http://homepages.cwi.nl/~arie/papers/dslbib/ )
> ... a domain-specific language (DSL) is a programming language or specification language dedicated to a particular problem domain, a particular problem representation technique, and/or a particular solution technique. ( http://en.wikipedia.org/wiki/Domain-specific_language )
> DSLs can be implemented either by interpretation or code generation. Interpretation (reading in the DSL script and executing it at run time) is usually easiest, but code-generation is sometimes essential. ( http://martinfowler.com/bliki/DomainSpecificLanguage.html )
[2] http://martinfowler.com/dslwip/UsingDsls.html#DefiningDomainSpecificLanguages
@mkovrov
ОтветитьУдалитьУ меня представления о DSL как о языке, который отличается от хост языка. swizard привёл два таких классических для CL примера - это loop и format. ASDF же наоборот, типичный CL. DSL вводят как язык, который лучше подходит для решаемой задачи. Поэтому нельзя говорить, что между API и DSL - тонкая грань, это просто разные вещи.
С каких пор вообще такой попсовик как Фаулер стал в авторитете?
В "представлении о DSL как о языке, который отличается от хост языка" Common Lisp не даёт ничего уникального в плане DSL.
ОтветитьУдалитьКак раз приспособление DSL под S-выражения и совместное использование DSL и CL -- это то, о чём все говорят, когда хвалят возможности лиспа в этом плане.
> Common Lisp не даёт ничего уникального в плане DSL.
ОтветитьУдалитьТак и есть. В CL просто проще реализовывать eDSL, но не более того.
> приспособление DSL под S-выражения и совместное
> использование DSL и CL
Отлично, но не любое s-выражение определяет DSL, а тот же format обходиться и без s-выражений. s-выражения могу использоваться для создания eDSL, а могу и не использоваться. s-выржения это просто характерный для CL инструмент.
> чём все говорят, когда хвалят возможности лиспа
> в этом плане.
Что-то хвалить, на мой взгляд, можно только на основе результатов практического использования. В open source проектах на CL DSL практически не используются. Так что это просто демагогия.
Вот в Haskell, как мне показалось, DSL действительно используются достаточно широко и там есть соответствующая интсрументальная поддержка.