мова з двома бінарними операторами однакового пріоритету, ліво-асоціативним та право-асоціативним


11

Чи є мова програмування (або сценаріїв) (або якась доменна мова), яка має два бінарні оператори oplі oprмає той самий пріоритет, що oplє лівоасоціативною та oprправо асоціативною?

(Я не можу знайти такий приклад, але я намагаюся зашифрувати якийсь загальний парсер, який достатньо загальний, щоб обробити цей дивний випадок)

Як би розбиралися вирази форми x opl y opr z або x opr y opl z ? І взагалі з ще більшою кількістю операндів?


4
Якщо болить, не робіть цього.
CodesInChaos

1
У Haskell ви можете визначити власні оператори інфікування з їх власними пріоритетами, і ви отримаєте помилку в цьому випадку; якщо у вас є x <@ y @> zз <@того левоассоціатівним і @>бути правоассоціатівним, GHC дає вам «помилку аналізу Precedence»: «не може змішувати" <@"[infixl 0] і" @>"[infixr 0] в тому ж вираженні інфіксне» (де я певен ці оператори на рівні 0 для прикладу).
Antal Spector-Zabusky

@ AntalSpector-Zabusky: Це була б чудова відповідь!
Базиль Старинкевич

@ AntalSpector-Zabusky: Те саме у Свіфта. Я думаю, ви можете насправді визначити операторів, але в виразі ви повинні використовувати всі ліві асоціативні або всі праві асоціативні оператори з однаковим пріоритетом. Таким чином, ви можете використовувати x leftop y leftop z, або x rightop y rightop z, але не x leftop y rightop z.
gnasher729

@BasileStarynkevitch: Як хочеш! Оскільки ви згадали про "гнучкі парсери", я включив ще кілька незрозумілих мов, які мають дуже гнучкі парсери (коли-небудь хотіли if_then_else_чи [1;2;3]визначалися в бібліотеках?).
Antal Spector-Zabusky

Відповіді:


10

Ось три мови, які дозволяють вам визначити власних операторів, які роблять дві з половиною різні речі! Хаскелл і Кок забороняють подібні шнанігани - але по-різному - в той час як Агда дозволяє подібне змішування асоціативностей.


По-перше, у Haskell вам просто не дозволено цього робити. Ви можете визначити власні оператори та надати їм перевагу (від 0 до 9) та асоціативність на ваш вибір. Однак звіт Haskell забороняє вас змішувати асоціативи :

Послідовні неопечатані оператори з однаковим пріоритетом повинні бути або лівими, або правими асоціативними, щоб уникнути помилки синтаксису. [Звіт Haskell 2010, гол. 3]

Так, у GHC , якщо ми визначаємо ліво-асоціативний ( infixl) оператор <@та правоасоціативний оператор @>на одному рівні пріоритетності - скажімо, 0 - тоді оцінювання x <@ y @> zдає помилку

Помилка розбору прецеденсу
    не може змішувати ' <@' [ infixl 0] і ' @>' [ infixr 0] в одному виразі інфіксації

(Насправді ви також можете оголосити оператора інфіксом, але неасоціативним, як ==, отже, x == y == zце синтаксична помилка!)


З іншого боку, є Agda (що, правда, значно менше мейнстріму). У Agda є один із найменш синтаксисних синтаксисів будь-якої моєї мови, що підтримує оператори змішування : стандартна бібліотека містить функцію

if_then_else_ : ∀ {a} {A : Set a} → Bool → A → A → A

який при дзвінку пишеться

if b then t else f

аргументи, що заповнюють підкреслення! Я згадую це, тому що це означає, що він повинен підтримувати неймовірно гнучку розбір. Природно, Agda також декларації нерухомості (хоча його рівні пріоритету пробігають довільні натуральні числа, і , як правило , в 0-100), і Agda робить дозволяє змішувати оператори з однаковим пріоритетом , але різні асоціативності і пріоритетів. Однак я не можу знайти інформацію про це в документації, тому мені довелося експериментувати.

Давайте повторно використаємо наше <@і @>зверху. У двох простих випадках у нас є

  • x <@ y @> zрозбір як x <@ (y @> z); і
  • x @> y <@ zрозбір як (x @> y) <@ z.

Я думаю, що Агда робить це згрупувати лінію в "лівий асоціативний" і "правий асоціативний" шматки, і - якщо я не думаю про речі неправильно - право-асоціативний шматок отримує "пріоритет" у захопленні суміжних аргументів. Отже, це дає нам

a <@ b <@ c @> d @> e @> f <@ g

розбір як

(((a <@ b) <@ (c @> (d @> (e @> f)))) <@ g

або

Розбір дерева <code> (((a <@ b) <@ (c @> (d </code> @> (e @> f)))) @ @ g

Однак, незважаючи на свої експерименти, я вгадав неправильно, коли перший раз написав це, що може бути повчальним :-)

(І в Agda, як і у Haskell, є неасоціативні оператори, які правильно дають помилки розбору, тому можливо, що і змішані асоціативи можуть призвести до помилки розбору.)


Нарешті, існує мова Coq , що підтверджує теорему / залежно від типу , яка має ще більш гнучкий синтаксис, ніж Agda, оскільки її розширення синтаксису реально реалізуються шляхом надання специфікацій для нових синтаксичних конструкцій, а потім переписування їх на основну мову (розпливчасто макроподібний , Я вважаю). У Coq синтаксис списку [1; 2; 3]- це необов'язковий імпорт із стандартної бібліотеки. Нові синтаксиси можуть навіть пов'язувати змінні!

Ще раз в Coq ми можемо визначити власні оператори інфіксації та надати їм рівні пріоритетності (здебільшого від 0 до 99) та асоціативності. Однак у Coq кожен рівень пріоритетності може мати лише одну асоціативність . Отже, якщо ми визначимо <@як ліво-асоціативний, а потім спробуємо визначити @>як право-асоціативний на тому ж рівні - скажімо, 50 - ми отримаємо

Помилка: рівень 50 вже оголошено лівим асоціативом, тоді як зараз очікується, що він буде правильним асоціативним

Більшість операторів у Coq знаходяться на рівнях, які поділяються на 10; якщо у мене виникли проблеми з асоціативністю (ці асоціації рівня є глобальними), я взагалі просто натрапив на рівень в будь-якому напрямку (як правило, вгору).


2
(Боже, який дивний вибір мов. Чи можете ви сказати, я вивчаю теорію мови програмування? :-P)
Antal Spector-Zabusky

Дякую великий добір за вашу детальну відповідь. До речі, як ти намалював малюнок (за допомогою якого інструменту graphviz?)
Базиль Старинкевич,

До речі, чому "фіксованість" замість "пріоритету"?
Василь Старинкевич

@BasileStarynkevitch: Це залежить від того, де ти маєш на увазі. Якщо ви маєте на увазі в розділі Coq, то це була лише помилка :-) (І це вже виправлено!)
Antal Spector-Zabusky

1
@BasileStarynkevitch: Також я пропустив ваше запитання про картинку! Я намалював це за допомогою пакета qtree LaTeX і вивів його в LaTeXit , фрагмент візуалізації LaTeX для Macs. Відповідний вихідний код був \ttfamily \Tree[.<@ [.<@ [.<@ a b ] [.@> c [.@> d [.@> e f ]]]] g ].
Antal Spector-Zabusky

2

З тих пір, як їх популяризував Дуглас Крокфорд, Pratt Parsers (або аналізатори прецедентів зверху вниз) почали набирати більше поширення. Ці парсери працюють із таблиці пріоритетності та асоціативності оператора, а не з правил, вбудованих у фіксовану граматику, тому вони корисні для мов, які дозволяють користувачам визначати власних операторів.

Вони мають функцію розбору, яка працює, спочатку аналізуючи крайній лівий член виразу, потім рекурсивно зв'язуючи нові оператори та умови правої руки, доки вони належним чином пов'язують. Ліво-асоціативні оператори прив'язують праворучні умови, які мають пріоритет до та включають той самий пріоритет, в той час як право-асоціативні оператори прив'язують лише до свого рівня пріоритетності, але не включаючи його. Я вважаю, що це призводить до того ж дерева розбору, що і у Agda, цитованого вище.

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