Языки программирования с Lisp-подобным механизмом расширения синтаксиса [закрыто]

20

У меня ограниченные знания Lisp (я стараюсь немного поучиться в свободное время), но насколько я понимаю, макросы Lisp позволяют вводить новые языковые конструкции и синтаксис, описывая их в самом Lisp. Это означает, что новая конструкция может быть добавлена ​​в виде библиотеки без изменения компилятора / интерпретатора Lisp.

Этот подход сильно отличается от других языков программирования. Например, если бы я хотел расширить Паскаль с помощью нового вида цикла или какой-то конкретной идиомы, мне пришлось бы расширить синтаксис и семантику языка и затем реализовать эту новую функцию в компиляторе.

Существуют ли другие языки программирования за пределами семейства Lisp (например, кроме Common Lisp, Scheme, Clojure (?), Racket (?) И т. Д.), Которые предлагают аналогичную возможность расширения языка внутри самого языка?

РЕДАКТИРОВАТЬ

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

Джорджио
источник
6
У Lisp есть еще один трюк, кроме обычных макросов. «Макросы чтения» позволяют захватывать и расширять синтаксический анализатор во время выполнения, поэтому даже базовая структура токенов языка находится под контролем.
ddyer
@ddyer: Спасибо, я не знал об этом: еще одна тема, которая будет добавлена ​​в мой список чтения.
Джорджио
Держу пари, что метапрограммирование Ruby может с этим справиться.
Буровая установка
1
Ваш вопрос противоречив, сначала вы запрашиваете список, затем вы спрашиваете о концептуальной информации, что это такое ???
Я прошу список, но не общий (не просто какой-либо язык программирования, который можно каким-либо образом расширить), потому что это будет слишком общим. Я хотел бы знать о языках, которые могут быть расширены способом, аналогичным Lisp (расширение определено с использованием того же языка, на котором оно расширяется, а не какого-то мета-языка). Ответы Петера Торока, Томаса Эдинга, SK-logic и Mechanical улитки кажутся наиболее близкими к тому, что я имел в виду. Я все еще должен внимательно прочитать все ответы.
Джорджио

Ответы:

19

Scala также делает это возможным (фактически, он был сознательно разработан для поддержки определения новых языковых конструкций и даже полных DSL).

Помимо функций высшего порядка, лямбда-выражений и карри, которые распространены в функциональных языках, здесь есть несколько специальных языковых функций, позволяющих это *:

  • без операторов - все функции, но имена функций могут включать специальные символы, такие как «+», «-» или «:»
  • точки и фигурные скобки могут быть опущены при вызове метода с одним параметром, то a.and(b)есть эквивалентно a and bв инфиксной форме
  • для однопараметрических вызовов функций вы можете использовать фигурные скобки вместо обычных скобок - это (вместе с каррингом) позволяет писать такие вещи, как

    val file = new File("example.txt")
    
    withPrintWriter(file) {
      writer => writer.println("this line is a function call parameter")
    }
    

    где withPrintWriterпростой метод с двумя списками параметров, каждый из которых содержит один параметр

  • параметры по имени позволяют опускать пустой список параметров в лямбдах, что позволяет записывать вызовы, как myAssert(() => x > 3)в более короткой форме, какmyAssert(x > 3)

Создание примера DSL подробно обсуждается в главе 11. Предметно-ориентированные языки в Scala бесплатной книги « Программирование Scala» .

* Я не имею в виду, что они уникальны для Scala, но, по крайней мере, они не очень распространены. Я не эксперт в функциональных языках, хотя.

Петер Тёрёк
источник
1
+1: интересно. Означает ли это, что для расширения синтаксиса я могу определять новые классы, и что сигнатуры методов будут предоставлять новый синтаксис как побочный продукт?
Джорджио
@ Джорджио, в основном да.
Петер Тёрёк
Ссылки больше не работают.
Нейт Гленн
13

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

  • Acme :: Bleach для действительно чистого кода
  • Acme :: Азбука Морзе для написания азбукой Морзе
  • Lingua :: Romana :: Perligata для написания на латинице (например, существительными являются переменные, а число, регистр и склонение изменяют тип существительного nextum ==> $ next, nexta ==> @next)

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

Более современный подход к этому в perl заключается в использовании Filter :: Simple (один из основных модулей в perl5).

Обратите внимание, что все эти примеры касаются Дамиана Конвея, которого называют «Безумный доктор Перла». Это все еще удивительно мощная способность в Perl крутить язык так, как он этого хочет.

Дополнительная документация для этой и других альтернатив существует в perlfilter .

user40980
источник
13

Haskell

На Haskell есть «Шаблон Haskell», а также «Квазиквотация»:

http://www.haskell.org/haskellwiki/Template_Haskell

http://www.haskell.org/haskellwiki/Quasiquotation

Эти функции позволяют пользователям существенно добавлять синтаксис языка за пределы обычных средств. Они также разрешаются во время компиляции, что, я думаю, является обязательным условием (по крайней мере, для скомпилированных языков) [1].

Я использовал квази-цитату в Haskell один раз, чтобы создать расширенный сопоставитель шаблонов на C-подобном языке:

moveSegment :: [Token] -> Maybe (SegPath, SegPath, [Token])
moveSegment [hc| HC_Move_Segment(@s, @s); | s1 s2 ts |] = Just (mkPath s1, mkPath s2, ts)
moveSegment _ = Nothing

[1] Иначе следующее квалифицируется как расширение синтаксиса: runFeature "some complicated grammar enclosed in a string to be evaluated at runtime"что, конечно, является грузом дерьма.

Томас Эдинг
источник
3
Есть также другие функции Haskell, которые по существу позволяют использовать собственный синтаксис, например, создание собственного оператора или автоматическое каррирование в сочетании с лямбда-функциями (рассмотрим, например, типичное использование forM).
Сион
Я, честно говоря, думаю, что карри и пользовательские операторы не имеют права. Они позволяют аккуратно использовать язык, но не позволяют добавлять / новые / функциональные возможности к языку. TH и QQ делают. В строгом смысле этого не делают TH и QQ в том смысле, что они делают именно то, для чего они предназначены, но они позволяют вам действительно выйти «из языка» во время компиляции.
Томас Эдинг
1
«Иначе следующее квалифицируется как расширение синтаксиса ...»: очень хороший момент.
Джорджио
12

Tcl имеет долгую историю поддержки расширяемого синтаксиса. Например, вот реализация цикла, который перебирает три переменные (до остановки) по кардиналам, их квадратам и кубам:

proc loopCard23 {cardinalVar squareVar cubeVar body} {
    upvar 1 $cardinalVar cardinal $squareVar square $cubeVar cube

    # We borrow a 'for' loop for the implementation...
    for {set cardinal 0} true {incr cardinal} {
        set square [expr {$cardinal ** 2}]
        set cube [expr {$cardinal ** 3}]

        uplevel 1 $body
    }
}

Это будет тогда использоваться так:

loopCard23 a b c {
    puts "got triplet: $a, $b, $c"
    if {$c > 400} {
        break
    }
}

Этот вид техники широко используется в программировании на Tcl, и ключом к его разумному выполнению являются команды upvarand uplevel( upvarсвязывает именованную переменную в другой области действия с локальной переменной и uplevelзапускает сценарий в другой области действия: в обоих случаях 1указывает, что рассматриваемая область является вызывающей стороной). Он также часто используется в коде, который соединяется с базами данных (запускает некоторый код для каждой строки в наборе результатов), в Tk для GUI (для привязки обратных вызовов к событиям) и т. Д.

Однако это только часть того, что сделано. Встроенный язык даже не должен быть Tcl; это может быть практически что угодно (пока он уравновешивает свои фигурные скобки - вещи становятся синтаксически ужасными, если это не так - что является огромным большинством программ), и Tcl может просто отправлять на встроенный иностранный язык по мере необходимости. Примеры этого включают в себя внедрение C для реализации команд Tcl и эквивалент с Fortran. (Возможно, все встроенные команды Tcl выполняются таким образом, в том смысле, что они на самом деле просто стандартная библиотека, а не сам язык.)

Donal Fellows
источник
10

Это частично вопрос семантики. Основная идея Lisp заключается в том, что программа - это данные, которыми можно манипулировать. Обычно используемые языки в семействе Lisp, такие как Scheme, на самом деле не позволяют добавлять новый синтаксис в смысле синтаксического анализатора; это всего лишь разделенные пробелами списки. Просто синтаксис ядра делает так мало, что из него можно сделать практически любую семантическую конструкцию. Scala (обсуждается ниже) похожа: правила имен переменных настолько либеральны, что вы можете легко сделать из них хорошие DSL (оставаясь в рамках тех же основных синтаксических правил).

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

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

  • Многие старые языки предоставляют встроенные функции, такие как sin(), round()и т. Д., Без какого-либо способа реализовать свои собственные.
  • C ++ предоставляет ограниченную поддержку. Например , некоторые встроенные в ключевых словах , как слепки ( static_cast<target_type>(input), dynamic_cast<>(), const_cast<>(), reinterpret_cast<>()) можно эмулировать с помощью функции шаблона, стимулирущие использует для lexical_cast<>(), polymorphic_cast<>(), any_cast<>(), ....
  • Java имеет встроенные структуры управления ( for(;;){}, while(){}, if(){}else{}, do{}while(), synchronized(){}, strictfp{}) и не позволяет определить свои собственные. Вместо этого Scala определяет абстрактный синтаксис, который позволяет вызывать функции с использованием удобного синтаксиса, похожего на структуру элемента управления, и библиотеки используют его для эффективного определения новых структур управления (например, react{}в библиотеке актеров).

Кроме того, вы можете взглянуть на пользовательский синтаксис Mathematica в пакете Notation . (Технически это относится к семейству Lisp, но имеет некоторые возможности расширения, сделанные по-другому, а также обычную расширяемость Lisp.)

Механическая улитка
источник
2
Неправильно. Lisp это на самом деле позволяет добавлять абсолютно любой новый синтаксис. Как в этом примере: meta-alternative.net/pfront.pdf - это не что иное, как макрос Lisp.
SK-logic
Кажется, это реализовано на языке, специально разработанном для создания DSL . Конечно, вы можете создать язык в семействе Лисп, который также предоставляет такие возможности; Я имел в виду, что эта особенность не является основной идеей Lisp, которая поддерживает bcommonly-используемый Lisps (например, Scheme). Отредактировано для уточнения.
Механическая улитка
Этот «язык для создания DSL» представляет собой набор макросов, построенных на основе довольно типичного минималистичного Lisp. Его можно легко перенести на любой другой Лисп с помощью (defmacro ...). На самом деле я сейчас портирую этот язык на Racket, просто для удовольствия. Но я согласен, что это что-то не очень полезное, поскольку синтаксиса S-выражений более чем достаточно для большинства возможных полезных семантических s.
SK-logic
Кроме того, Scheme ничем не отличается от Common Lisp, начиная с R6RS официально, и неофициально на века, поскольку она предоставляет (define-macro ...)эквивалент, который, в свою очередь, может использовать любой вид анализа внутри системы.
SK-logic
8

Rebol звучит почти как то, что вы описываете, но немного сбоку.

Вместо того, чтобы определять конкретный синтаксис, все в Rebol - это вызов функции - здесь нет ключевых слов. (Да, вы можете переопределить ifи whileесли вы действительно хотите). Например, это ifутверждение:

if now/time < 12:00 [print "Morning"]

ifэто функция, которая принимает 2 аргумента: условие и блок. Если условие истинно, блок оценивается. Похоже на большинство языков, верно? Ну, блок - это структура данных, он не ограничен кодом - это, например, блок блоков и быстрый пример гибкости «код - данные»:

SomeArray: [ [foo "One"] [bar "Two"] [baz "Three"] ]
foreach action SomeArray [action/1: 'print] ; Change the data
if now/time < 12:00 SomeArray/2 ; Use the data as code - right now, if now/time < 12:00 [print "Two"]

Пока вы можете придерживаться правил синтаксиса, расширение этого языка, по большей части, будет не чем иным, как определением новых функций. Некоторые пользователи перенесли функции Rebol 3 в Rebol 2, например.

Izkata
источник
7

У Ruby довольно гибкий синтаксис, я думаю, что это способ «расширить язык внутри самого языка».

Примером являются грабли . Он написан на Ruby, это Ruby, но выглядит как make .

Чтобы проверить некоторые возможности, вы можете поискать ключевые слова Ruby и метапрограммирование .

Кнут
источник
13
«гибкий синтаксис» ОЧЕНЬ отличается от «расширяемого синтаксиса». Прошло много времени с тех пор, как я программировал на Ruby, но Rake выглядит как хорошо спроектированное использование встроенного синтаксиса. Другими словами, это не пример.
Томас Эдинг
2
Разве это не вопрос степени, не по виду? Как бы вы различали язык «расширяемого синтаксиса», который может расширять некоторые аспекты своего синтаксиса, но не другие, и язык «гибкого синтаксиса»?
Грядущая буря
1
Если линия размыта, давайте отодвинем ее назад так, чтобы считалось, что C поддерживает расширяемый синтаксис.
Томас Эдинг
Чтобы связать ваш пример, я бы подвел черту здесь: язык с расширяемым синтаксисом может делать rake, который выглядит как make. Язык с гибким синтаксисом может быть расширен (ха, хорошее лингвистическое смешение) для компиляции и запуска make-файлов. Ваша точка зрения на степень важна, хотя. Возможно, некоторые языки позволяют компилировать Make, но не Python. А другие позволят и то и другое.
Клейтон Стэнли,
Любой тьюринговый полный язык должен быть способен обрабатывать файлы Make. Гибкость синтаксиса не является фактором, выходящим за рамки сложности.
Буровая установка
7

Расширение синтаксиса так, как вы говорите, позволяет создавать языки, специфичные для предметной области. Поэтому, возможно, самый полезный способ перефразировать ваш вопрос: какие другие языки имеют хорошую поддержку для языков, специфичных для предметной области?

У Ruby очень гибкий синтаксис, и там процветает множество DSL, таких как rake. Groovy включает в себя много этого добра. Он также включает в себя преобразования AST, которые более прямо аналогичны макросам Lisp.

R, язык для статистических вычислений, позволяет функциям получать свои аргументы без оценки. Он использует это для создания DSL для определения формулы регрессии. Например:

y ~ a + b

означает «подгонка строки вида k0 + k1 * a + k2 * b к значениям в y».

y ~ a * b

означает «соответствовать строке вида k0 + k1 * a + k2 * b + k3 * a * b значениям в y».

И так далее.

Мартин С. Мартин
источник
2
Преобразования AST в Groovy очень многословны по сравнению с макросами Lisp или Clojure. Например, 20-строчный пример Groovy на groovy.codehaus.org/Global+AST+Transformations может быть переписан как одна короткая строка в Clojure, например `(this (println ~ message)). Не только это, но вам также не нужно будет скомпилировать jar, записать метаданные или любой другой материал на этой странице Groovy.
Ворг ван Гейр
7

Конвергенция - это еще один язык без метаний. И, в некоторой степени, C ++ тоже подходит.

Возможно, MetaOCaml довольно далеко от Lisp. Для совершенно другого стиля расширения синтаксиса, но все же достаточно мощного, взгляните на CamlP4 .

Nemerle - еще один расширяемый язык с метапрограммированием в стиле Lisp, хотя он ближе к таким языкам, как Scala.

И сама Scala скоро тоже станет таким языком.

Редактировать: я забыл о самом интересном примере - JetBrains MPS . Это не только очень далеко от всего Лиспиша, это даже нетекстовая система программирования с редактором, работающим непосредственно на уровне AST.

Edit2: чтобы ответить на обновленный вопрос - нет ничего уникального и исключительного в макросах Lisp. Теоретически, любой язык может обеспечить такой механизм (я даже сделал это с простым C). Все, что вам нужно, это доступ к вашему AST и возможность выполнять код во время компиляции. Может помочь некоторое размышление (запрос о типах, существующих определениях и т. Д.).

СК-логика
источник
Ваша ссылка Scala явно говорит о том, что предлагаемые макросы "не могут изменить синтаксис Scala". (Интересно, это перечисляет разницу между этим предложением и макросами препроцессора C / C ++!)
ruakh
@ruakh, да, это тот же подход, что и Converge и Template Haskell - макрос приложения явно помечен и не может быть смешан с «нормальным» синтаксисом. Но внутри вы можете иметь любой синтаксис, который вам нравится, поэтому, возможно, это расширяемый синтаксис. К сожалению, требование «неиспользования» ограничивает ваши возможности такими языками.
SK-logic
«Я даже сделал это с простым C»: как это возможно?
Джорджио
@Giorgio, конечно, я модифицировал компилятор (добавил макросы и инкрементную компиляцию модуля, что на самом деле вполне естественно для C).
SK-logic
Зачем нужен доступ к AST?
Эллиот Гороховский
6

Пролог позволяет определять новые операторы, которые переводятся в составные термины с тем же именем. Например, это определяет has_catоператор и определяет его как предикат для проверки, содержит ли список атом cat:

:- op(500, xf, has_cat).
X has_cat :- member(cat, X).

?- [apple, cat, orange] has_cat.
true ;
false.

В xfозначает , что has_catпостфиксный оператор; использование fxсделало бы его префиксным оператором и xfxсделало бы его инфиксным оператором, принимающим два аргумента. Проверьте эту ссылку для более подробной информации об определении операторов в Прологе.

Амброз Бижак
источник
5

TeX полностью отсутствует в списке. Вы все это знаете, верно? Это выглядит примерно так:

Some {\it ``interesting''} example.

... за исключением того, что вы можете переопределить синтаксис без ограничений. Каждому (!) Токену в языке может быть присвоено новое значение. ConTeXt - это макропакет, который заменил фигурные скобки квадратными скобками:

Some \it[``interesting''] example.

Более распространенный пакет макросов LaTeX также переопределяет язык для своих целей, например, добавляя \begin{environment}…\end{environment}синтаксис.

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

Some <it>“interesting”</it> example.

Да, абсолютно возможно. Некоторые пакеты используют это для определения небольших специфичных для домена языков. Например, пакет TikZ определяет краткий синтаксис для технических чертежей, который позволяет следующее:

\foreach \angle in {0, 30, ..., 330} 
  \draw[line width=1pt] (\angle:0.82cm) -- (\angle:1cm);

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

for word in [Some interesting example.]:
    if word == interesting:
        it(word)
    else:
        word
Конрад Рудольф
источник
5

Boo позволяет настраивать язык во время компиляции с помощью синтаксических макросов.

У Boo есть «расширяемый конвейер компилятора». Это означает, что компилятор может вызывать ваш код для выполнения преобразований AST в любой точке конвейера компилятора. Как вы знаете, такие вещи, как Generics в Java или Linq в C #, являются просто синтаксическими преобразованиями во время компиляции, так что это довольно мощно.

По сравнению с Лиспом главное преимущество заключается в том, что это работает с любым синтаксисом. Boo использует Python-вдохновленный синтаксис, но вы, вероятно, могли бы написать расширяемый компилятор с синтаксисом C или Pascal. А поскольку макрос оценивается во время компиляции, производительность не снижается.

Недостатками по сравнению с Лиспом являются:

  • Работа с AST не так элегантна, как работа с s-выражениями
  • Поскольку макрос вызывается во время компиляции, он не имеет доступа к данным времени выполнения.

Например, вот как вы можете реализовать новую структуру управления:

macro repeatLines(repeatCount as int, lines as string*):
    for line in lines:
        yield [| print $line * $repeatCount |]

использование:

repeatLines 2, "foo", "bar"

который затем переводится во время компиляции в нечто вроде:

print "foo" * 2
print "bar" * 2

(К сожалению, онлайн-документация Boo всегда безнадежно устарела и даже не охватывает такие сложные вещи, как этот. Лучшая документация для языка, который я знаю, это книга: http://www.manning.com/rahien/ )

nikie
источник
1
Веб-документация по этой функции в настоящее время не работает, и я сам не пишу Boo, но я подумал, что было бы жаль, если бы ее не заметили. Я ценю обратную связь с модом и буду пересматривать, как я делюсь о предоставлении бесплатной информации в свободное время.
Дэн
4

Оценка Mathematica основана на сопоставлении с образцом и его замене. Это позволяет вам создавать свои собственные структуры управления, изменять существующие структуры управления или изменять способ оценки выражений. Например, вы можете реализовать «нечеткую логику» следующим образом (немного упрощенно):

fuzzy[a_ && b_]      := Min[fuzzy[a], fuzzy[b]]
fuzzy[a_ || b_]      := Max[fuzzy[a], fuzzy[b]]
fuzzy[!a_]           := 1-fuzzy[a]
If[fuzzy[a_], b_,c_] := fuzzy[a] * fuzzy[b] + fuzzy[!a] * fuzzy[c]

Это переопределяет оценку для предопределенных логических операторов &&, || ,! и встроенная Ifоговорка.

Вы можете прочитать эти определения как определения функций, но реальное значение таково: если выражение соответствует шаблону, описанному слева, оно заменяется выражением справа. Вы можете определить свое собственное предложение If следующим образом:

myIf[True, then_, else_] := then
myIf[False, then_, else_] := else
SetAttributes[myIf, HoldRest]

SetAttributes[..., HoldRest] говорит оценщику, что он должен оценить первый аргумент перед сопоставлением с образцом, но оставить оценку для остальных до тех пор, пока образец не будет сопоставлен и заменен.

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

оборота ники
источник
3

Metalua - это язык и компилятор, совместимый с Lua, который обеспечивает это.

  • Полная совместимость с исходными кодами Lua 5.1 и байт-кодом: чистая, элегантная семантика и синтаксис, потрясающая выразительная мощь, хорошие характеристики, почти универсальная переносимость. - Полная система макросов, схожая по мощности с тем, что предлагает диалекты Лисп или Шаблон Хаскелла; Манипулируемые программы могут рассматриваться
    как исходный код, как деревья абстрактного синтаксиса или как их произвольное сочетание
    , в зависимости от того, что лучше подходит для вашей задачи.
  • Динамически расширяемый синтаксический анализатор, который позволяет поддерживать ваши макросы с помощью синтаксиса, который прекрасно сочетается с остальным языком.

  • Набор языковых расширений, все реализовано в виде обычных макросов metalua.

Отличия от Лисп:

  • Не мешайте разработчикам макросов, когда они не пишут один: синтаксис и семантика языка должны лучше всего подходить для тех 95% случаев, когда мы не пишем макросы.
  • Поощряйте разработчиков следовать языковым соглашениям: не только с «лучшими практиками», которые никто не слушает, но и предлагая API, который облегчает написание вещей в стиле Metalua. Читаемость другими разработчиками важнее и труднее достичь, чем читаемость компиляторами, и для этого очень помогает наличие общего набора уважаемых соглашений.
  • И все же предоставьте всю силу, с которой вы готовы справиться. Ни Lua, ни Metalua не находятся в обязательном рабстве и дисциплине, поэтому, если вы знаете, что делаете, язык не будет вам мешать.
  • Сделайте это очевидным, когда происходит что-то интересное: все мета-операции происходят между + {...} и - {...} и визуально выпадают из обычного кода.

Примером применения является реализация ML-подобного сопоставления с образцом.

Смотрите также: http://lua-users.org/wiki/MetaLua

Климент Дж.
источник
Хотя Lua на самом деле не Лисп, ваш список «отличий» довольно подозрительный (единственный релевантный элемент - последний). И, конечно же, сообщество Lisp не согласится с утверждением, что не следует писать / использовать макросы 95% времени - способ, которым пользуется Lisp, примерно в 95% случаев использует и записывает DSL поверх макросов курс.
SK-logic
2

Если вы ищете расширяемые языки, вам стоит взглянуть на Smalltalk.

В Smalltalk единственным способом программирования является расширение языка. Нет никакой разницы между IDE, библиотеками или самим языком. Они все так переплетены, что Smalltalk часто называют скорее средой, а не языком.

Вы не пишете автономные приложения в Smalltalk, вместо этого вы расширяете языковую среду.

Проверьте http://www.world.st/ для нескольких ресурсов и информации.

Я хотел бы рекомендовать Pharo как диалект входа в мир Smalltalk: http://pharo-project.org

Надеюсь, это помогло!

оборота Бернат Ромагоса
источник
1
Звучит интересно.
Томас Эдинг
1

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

Таким образом, можно было бы взять грамматику языка X, определить грамматику языка X '(X с вашими собственными расширениями) и преобразование X' → X, и Spoofax сгенерирует компилятор X '→ X.

В настоящее время, если я правильно понимаю, лучшая поддержка для Java, с развитием поддержки C # (или я так слышал). Этот метод может быть применен к любому языку со статической грамматикой (например, возможно, не к Perl ).

liori
источник
1

Forth - другой язык, который является очень расширяемым. Многие реализации Forth состоят из небольшого ядра, написанного на ассемблере или C, тогда остальная часть языка написана на самом Forth.

Есть также несколько основанных на стеке языков, которые вдохновлены Forth и разделяют эту функцию, такие как Factor .

Дейв Кирби
источник
0

Funge-98

Функция распознавания отпечатков пальцев в Funge-98 позволяет полностью реструктурировать весь синтаксис и семантику языка. Но только в том случае, если разработчик предоставляет механизм распознавания отпечатков пальцев, который позволяет пользователю программно изменять язык (это теоретически возможно реализовать в рамках нормального синтаксиса и семантики Funge-98). Если это так, можно буквально заставить остальную часть файла (или любые другие части файла) действовать как C ++ или Lisp (или все, что он хочет).

http://quadium.net/funge/spec98.html#Fingerprints

Томас Эдинг
источник
почему вы разместили это отдельно, а не добавили в свой предыдущий ответ ?
Комнат
1
Потому что Funge не имеет ничего общего с Haskell.
Томас Эдинг
-1

Чтобы получить то, что вы ищете, вам действительно нужны эти скобки и отсутствие синтаксиса. Несколько основанных на синтаксисе языков могут быть близки, но это не совсем то же самое, что настоящий макрос.

mike30
источник