Мови програмування з механізмом розширення синтаксису, подібного до Lisp [закрито]


20

У мене є лише обмежені знання про Lisp (намагаючись навчитися трохи у вільний час), але, наскільки я розумію, макроси Lisp дозволяють вводити нові мовні конструкції та синтаксис, описуючи їх у самому Lisp. Це означає, що нову конструкцію можна додати як бібліотеку, не змінюючи компілятор / інтерпретатор Lisp.

Цей підхід сильно відрізняється від інших мов програмування. Наприклад, якби я хотів розширити Паскаль на новий тип циклу чи якусь конкретну ідіому, я мав би розширити синтаксис та семантику мови, а потім реалізувати цю нову функцію у компіляторі.

Чи існують інші мови програмування поза сім’єю Lisp (тобто, крім Common Lisp, Scheme, Clojure (?), Racket (?) Тощо), які пропонують подібну можливість поширити мову в межах самої мови?

EDIT

Будь ласка, уникайте розширених дискусій та будьте конкретні у своїх відповідях. Замість довгого списку мов програмування, який можна розширити тим чи іншим способом, я хотів би зрозуміти з концептуальної точки зору, що є специфічним для макросів Lisp як механізму розширення, і які мови, які не є програмами Lisp, пропонують певну концепцію що близько до них.


6
У Lisp є ще одна хитрість, крім звичайних макросів. "Макроси читання" дозволяють захоплювати та розширювати синтаксис синтаксису під час виконання, тому навіть основна структура лексеми мови знаходиться під контролем.
ddyer

@ddyer: Дякую, я про це не знав: ще одна тема повинна бути додана до мого списку читання.
Джорджіо

Я би ставлю, що метапрограмування Ruby може це задовольнити.
Ріг

1
ваше питання суперечливе, спочатку ви запитуєте список, потім ви запитуєте концептуальну інформацію, що це таке ???

Я прошу список, але не загальний (не просто будь-яку мову програмування, яку можна якось розширити), оскільки це було б занадто загальним. Мені хотілося б знати мови, які можна розширити таким чином, як Lisp (розширення визначається за допомогою тієї самої мови, що і розширення, а не якоюсь мета-мовою). Відповіді Петера Тьорека, Томаса Едінга, SK-логіки та Механічного равлика здаються найближчими до того, що я мав на увазі. Я все ще повинен уважно прочитати всю відповідь.
Джорджіо

Відповіді:


19

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

Окрім функцій вищого порядку, лямбдасів та каррі, які є загальними для функціональних мов, тут є деякі особливі мовні особливості, щоб це увімкнути *:

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

    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: Цікаво. Чи означає це, що для розширення синтаксису я можу визначити нові класи і що підписи методу нададуть новий синтаксис як побічний продукт?
Джорджіо

@Giorgio, в основному так.
Péter Török

Посилання більше не працюють.
Нейт Гленн

13

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

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

Існує також модуль, який дозволяє Perl запускати код, схожий на те, що він був написаний на Python.

Більш сучасним підходом до цього в perl було б використання Filter :: Simple (один з основних модулів в perl5).

Зауважте, що всі ці приклади стосуються Даміана Конвей, якого називають "безумним лікарем Перла". Це все-таки дивовижно потужна здатність всередині perl скручувати мову так, як хто хоче.

Більше документації для цієї та інших альтернатив існує у perlfilter .


13

Хаскелл

У Haskell є "Шаблон Haskell", а також "Quasiquotation":

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

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

Ці функції дозволяють користувачам різко додавати синтаксис мови поза звичайними засобами. Вони також вирішуються під час компіляції, що, на мою думку, є великим обов'язком (як мінімум для компільованих мов) [1].

Я раніше використовував квазіквітацію в Haskell, щоб створити розширений відповідник шаблонів на мові, подібній С:

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).
Xion

Я чесно думаю, що каррінг та користувацькі оператори не відповідають вимогам. Вони дозволяють користувачеві акуратно користуватися мовою, але не дозволяють додавати / нову / функціональну мову. 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, і ключовим для його виконання є ключові команди upvarта uplevelкоманди ( upvarприв'язує названу змінну в іншій області до локальної змінної та uplevelзапускає сценарій в іншій області: в обох випадках 1вказується, що сфера, про яку йдеться, - абонент). Також багато використовується в коді, який з'єднується з базами даних (працює якийсь код для кожного ряду в наборі результатів), в Tk для графічних інтерфейсів (для прив’язки зворотних викликів до подій) тощо.

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


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-логіка

Це, здається, реалізовано мовою, спеціально розробленою для створення DSL . Звичайно, можна створити мову в сім'ї Лісп, яка також надає такі функції; Я мав на увазі, що ця функція не є основною ідеєю Lisp, підтримуваною настільки часто використовуваними Lisps (наприклад, Схема). Відредаговано для уточнення.
Механічний равлик

Ця "мова для побудови DSL" - це колекція макросів, побудованих поверх досить типового, мінімалістичного Lisp. Його можна легко перенести на будь-який інший Lisp (defmacro ...). Насправді я зараз переношу цю мову в Ракетку, просто заради розваги. Але я погоджуюся, що це щось не дуже корисне, оскільки синтаксис S-виразів більш ніж достатній для більшості можливих корисних семантичних s.
SK-логіка

Крім того, схема нічим не відрізняється від Common Lisp, починаючи з R6RS офіційно, і неофіційно для віків, оскільки вона дає (define-macro ...)еквівалент, який, в свою чергу, може використовувати будь-який вид розбору всередині.
SK-логіка

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.


7

У Рубі досить гнучкий синтаксис, я думаю, це спосіб "розширити мову всередині самої мови".

Приклад - граблі . Це написано в Ruby, це Ruby, але це схоже на make .

Щоб перевірити деякі можливості, ви можете шукати ключові слова Ruby та метапрограмування .


13
"гнучкий синтаксис" ДУЖЕ відрізняється від "розширюваного синтаксису". Минуло багато часу, як я запрограмував у Ruby, але Rake виглядає як добре продумане використання вбудованого синтаксису. Іншими словами, це неприклад.
Томас Едінг

2
Це не ступінь, а не вид? Як би ви відрізнили мову "розширюваного синтаксису", яка може розширити деякі аспекти її синтаксису, але не інші, та "гнучку синтаксичну" мову?
прийде штурм

1
Якщо лінія розмита, тоді давайте відсунемо лінію, щоб C вважав, що підтримує розширюваний синтаксис.
Томас Едінг

Щоб зв’язатись із вашим прикладом, я би намалював тут лінію: Мова з розширюваним синтаксисом може зробити рейку, що схоже на make. Мова з гнучким синтаксисом може бути розширена (га, приємне мовне змішування там) для компіляції та запуску файлів. Хоча ваша думка з точки зору ступеня хороша. Можливо, деякі мови дозволяють компілювати Make, але не Python. А інші дозволили б і те, і інше.
Клейтон Стенлі

Будь-яка мовна цілісна мова повинна бути спроможна зробити обробку файлів. Гнучкість синтаксису не є важливим фактором, який би не був викликом.
Риг

7

Розширення синтаксису способом, про який ви говорите, дозволяє створювати мови, що відповідають домену. Тож, мабуть, найкорисніший спосіб переформулювати своє запитання - які інші мови мають гарну підтримку для мов, що належать до домену?

У Ruby дуже гнучкий синтаксис, і багато DSL розквітло там, наприклад, граблі. Groovy включає багато цього добра. Він також включає перетворення AST, які є більш аналогічними макросам Lisp.

R, мова статистичних обчислень, дозволяє функціям отримувати свої аргументи неоціненими. Він використовує це для створення DSL для визначення формули регресії. Наприклад:

y ~ a + b

означає "підходити рядок форми k0 + k1 * a + k2 * b до значень у".

y ~ a * b

означає "підходити рядок форми k0 + k1 * a + k2 * b + k3 * a * b до значень у".

І так далі.


2
Перетворення AST Groovy дуже багатослівні в порівнянні з макросами Lisp або Clojure. Наприклад, приклад Groovy 20+ за адресою groovy.codehaus.org/Global+AST+Transformations може бути переписаний у Clojure як один короткий рядок, наприклад `(це (println ~ повідомлення)). Мало того, але вам також не доведеться складати банку, писати метадані або будь-який інший матеріал на цій сторінці Groovy.
Vorg van Geir

7

Конвергенція - ще одна неліпична мова метапрограмування. І певною мірою кваліфікується і C ++.

Можливо, MetaOCaml знаходиться досить далеко від Ліспа. Для абсолютно іншого стилю розширення синтаксису, але при цьому досить потужного, погляньте на CamlP4 .

Немерле - ще одна розширювана мова з метапрограмуванням у стилі Лісп, хоча вона ближче до таких мов, як Scala.

І незабаром стане сама Скала такою мовою.

Редагувати: я забув про найцікавіший приклад - JetBrains MPS . Він не тільки дуже віддалений від всього ліспішського, це навіть нетекстова система програмування, з редактором, який працює безпосередньо на рівні AST.

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


Ваш посилання Scala прямо говорить, що запропоновані макроси "не можуть змінити синтаксис Scala". (Цікаво, що він перераховує це як різницю між цією пропозицією та макросами препроцесора C / C ++!)
ruakh

@ruakh, так, це той самий підхід, що і для конвергенції та шаблону Haskell - додаток макросу явно позначений і не може бути змішаний із "нормальним" синтаксисом. Але всередині ви можете мати будь-який синтаксис, який вам подобається, тому, певно, це синтаксис, що розширюється. Вимога "non-lisp", на жаль, обмежує ваші параметри такими мовами.
SK-логіка

"Я навіть це робив із звичайним С": Як це можливо?
Джорджіо

@ Giorgio, звичайно, я змінив компілятор (додав макроси та компіляцію інкрементального модуля, що насправді цілком природно для C).
SK-логіка

Чому необхідний доступ до AST?
Елліот Гороховський

6

Prolog дозволяє визначити нових операторів, які переведені на складені однойменні терміни. Наприклад, це визначає 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зробить його оператором інфіксації, взявши два аргументи. Перейдіть за цим посиланням для отримання більш детальної інформації про визначення операторів у Prolog.


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 є Turing завершеним, так що ви можете буквально зробити все з цим. Я ніколи не бачив, щоб це було використане на весь його потенціал, тому що це було б досить безглуздо і дуже заплутано, але цілком можливо зробити наступний код розбірливим лише шляхом перевизначення лексем (але це, ймовірно, піде на фізичні межі парсера, через спосіб його побудови):

for word in [Some interesting example.]:
    if word == interesting:
        it(word)
    else:
        word

5

Бу дозволяє вам сильно налаштувати мову під час компіляції за допомогою синтаксичних макросів.

Boo має "розширюваний конвеєрний компілятор". Це означає, що компілятор може зателефонувати на ваш код, щоб зробити перетворення AST в будь-якій точці під час конвеєра компілятора. Як відомо, такі речі, як Java Generics або C #'s Linq, є лише синтаксичними перетвореннями під час компіляції, тому це досить потужно.

Порівняно з Lisp, головна перевага полягає в тому, що це працює з будь-яким синтаксисом. 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

(На жаль, Інтернет-документація Бу завжди застає безнадійно застарілою і навіть не охоплює подібних матеріалів. Найкраща документація для мови, яку я знаю, - це ця книга: http://www.manning.com/rahien/ )


1
Зараз веб-документація для цієї функції зламана, і я сам не пишу Бу, але я подумав, що шкода, якщо його не помітити. Я вдячний за відгуки про мод і перегляну, як я збираюсь надавати безкоштовну інформацію у вільний час.
День

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: чиста, елегантна семантика та синтаксис, дивовижна виразність, хороші характеристики, майже універсальна портативність. - Повна макросистема, подібна за потужністю до того, що пропонується діалектами Ліспа або Шаблоном Хаскелл; маніпульовані програми можуть розглядатися
    як вихідний код, як абстрактні синтаксичні дерева або як довільна
    їх суміш , залежно від того, що краще відповідає вашій задачі.
  • Динамічно розширюваний парсер, який дозволяє підтримувати ваші макроси синтаксисом, який добре поєднується з рештою мови.

  • Набір розширень мови, всі реалізовані як звичайні макроси металуї.

Відмінності від Lisp:

  • Не обтяжуйте розробників макросами, коли вони не пишуть: синтаксис та семантика мови повинні найкраще підходити для тих 95% часу, коли ми не пишемо макроси.
  • Заохочуйте розробників дотримуватися мовних положень: не тільки з "кращими практиками", які ніхто не слухає, але, пропонуючи API, який полегшує запис речей Metalua Way. Читання читачами-розробниками важливіше і важче досягти, ніж читабельність компіляторами, і для цього багато спільного набору дотриманих конвенцій допомагає дуже багато.
  • І все-таки надайте всю силу, з якою люди готові впоратися. Ні Луа, ні Металуа не впадають у обов'язковість неволі та дисципліни, тож якщо ви знаєте, що робите, мова не завадить вам.
  • Зробити це очевидним, коли трапляється щось цікаве: всі метаоперації відбуваються між + {...} і - {...}, і візуально стикаються зі звичайного коду.

Прикладом застосування є реалізація відповідності шаблонів, подібних ML.

Дивіться також: http://lua-users.org/wiki/MetaLua


Хоча Луа справді не є Ліспом, ваш список "відмінностей" є досить підозрілим (єдиний відповідний пункт - останній). І, звичайно, спільнота Лісп не погодилася б з тим, що не слід писати / використовувати макроси 95% часу - Лісп нахиляється до чогось 95% часу, використовуючи та записуючи DSL, поверх макросів, звичайно.
SK-логіка

2

Якщо ви шукаєте розширювані мови, вам варто поглянути на Smalltalk.

У Smalltalk єдиний спосіб програмування - це фактично розширити мову. Немає різниці між IDE, бібліотеками або самою мовою. Всі вони настільки сплетені, що Малую розмову часто називають середовищем, а не мовою.

Ви не пишете автономні програми в 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 ).


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

Щоб отримати те, що ви шукаєте, вам дійсно потрібні ці круглі дужки та відсутність синтаксису. Кілька мов на основі синтаксису можуть наблизитися, але це не зовсім те саме, що справжній макрос.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.