#haskell #syntax
#haskell #синтаксис
Вопрос:
Прошу прощения за расплывчатый заголовок вопроса; Я не смог найти правильный.
Несколько лет назад я наткнулся на страницу (полагаю, на Haskell Prime wiki) предложения по расширению языка. Предположим, что код Haskell типа:
f1 (f2 v1 v2 v3) (f3 v4 v5 v6)
и, допустим f2 v1 ...
, часть имеет длинные имена функций и имена значений, что делает всю строку намного длиннее, чем хотелось бы, и ее труднее читать. Мы хотели бы изменить его на
f1
(f2 v1 v2 v3)
(f3 v4 v5 v6)
который более удобочитаем и будет представлять структуру намного более четко, т. Е. Что является аргументом для чего. Но тогда, если у нас есть более сложное отношение, например
f1
(f2 (f3 v1) (f4 v2) v3)
(f5 v4)
(f7 v5)
тогда он очень быстро становится неопрятным, и скобки выходят из-под контроля.
В идеале мы могли бы
f1
f2
f3 v1
f4 v2
v3
f5 v4
f7 v5
Таким образом, структура понятна как для человека, так и для машины. Но поскольку это было невозможно в стандарте Haskell, кучка умных парней придумала идею расширения языка, позволяющего использовать новый оператор. Оператор выглядел как $
, но имел другую ассоциативность. Допустим, оно вызвано $$
, тогда:
f1 $$
f2 v1 v2 v3
f3 v4 v5 v6
было бы эквивалентно f1 (f2 v1 v2 v3) (f3 v4 v5 v6)
и
f1 $$
f2 $$
f3 v1
f4 v2
v3
f5 v4
f7 v5
будет переведено на f1 (f2 (f3 v1) (f4 v2) v3) (f5 v4) (f7 v5)
.
Я бы хотел использовать расширение GHC для этой функции, потому что реализация DSL с древовидной структурой была бы простой, но я вообще не смог найти ни одного ресурса.
- Как называется эта концепция (и оператор, который я вызвал
$$
)? - Есть ли уже расширение GHC для этого?
- Если нет, я был бы очень признателен за ссылки на любое другое связанное расширение. Я готов узнать, как написать расширение GHC для реализации этого.
Редактировать: я знаю, что существует много обходных путей, включая шаблон Haskell QQ и круглые скобки, но я помню, что видел предложение по расширению языка, и мой вопрос касается этого расширения, а не других способов решения проблемы.
Кстати, я очень неохотно рассматриваю возможность использования круглых скобок, потому что заключение в скобки сложной вложенной структуры сделает ее очень загроможденной и сведет на нет весь смысл разметки кода на основе отступов. Преимущество синтаксиса «внешнего правила» перед синтаксисом «фигурных скобок» ставится под угрозу, если вам приходится заключать практически все в скобки и вручную стилизовать его, чтобы он выглядел структурированным. Я почти уверен, что есть много хаскеллеров, которые считают это нечистым, как это наблюдается в библиотеках на основе моноидов, имеющих бессмысленный экземпляр monad (и пустое значение для передачи), чтобы использовать do
синтаксис. Пока они могут писать
example = mappend
[ lorem ipsum
, dolor amet
]
они предпочитают объявлять экземпляр монады и писать
example = do
lorem ipsum
dolor amet
не потому, что это имеет больше смысла с точки зрения типа, а потому, что оно просто выглядит чистым и лаконичным. (На самом деле проблема со скобками хуже, чем со скобками, потому что вам нужно вставить почти в два раза больше специальных символов, чтобы представить структуру приложения функции.) Это также значительно уменьшило бы вероятность пропуска символов по ошибке, что в точности является преимуществом языков сторонних правил по сравнению с языками фигурных скобок. В лучшем случае пропущенные или неуместные скобки, скобки или запятые приведут к ошибке во время компиляции, а в худшем — к ошибочной программе, которая делает что-то дикое и непреднамеренное.
Комментарии:
1. Неясно, зачем нужны и расширение, и оператор.
2. Вам нужны как расширение, так и оператор, потому что в противном случае вы не сможете добавить код нового стиля в существующий код старого стиля. Если нет нового оператора, включение расширения сделает
antb c
always meana (b c)
и nevera b c
.3. Почему бы просто не сделать отступ, как в вашем четвертом фрагменте кода, но сохранить круглые скобки?
Ответ №1:
Мне наконец удалось найти страницу, поэтому я отвечу на свой собственный вопрос.
Это называется компоновкой приложения. Оно было предложено после компоновки monoid, в которой предлагается новое ключевое be
слово (или mdo
), которое устранило бы необходимость в бессмысленных экземплярах monad для получения do
обозначения.
Ответ №2:
Если вы хотите встроить свой пользовательский синтаксис в GHC Haskell, вы можете попробовать Quasiquoters .
Бесстыдное копирование из связанных примеров, квазиквоттинг может превратить синтаксис в
[expr|1 3|]
в
BinopExpr AddOp (IntExpr 1) (IntExpr 3)
где
data Expr = IntExpr Integer
| AntiIntExpr String
| BinopExpr BinOp Expr Expr
| AntiExpr String
data BinOp = AddOp | SubOp | MulOp | DivOp
Вам нужно создать свой собственный анализатор, превращающий строки, такие как «1 3», в фактическое представление термина. В вашем случае вам нужно будет разобраться с отступами самостоятельно.
Комментарии:
1. Спасибо. Я знал, что QQ смог справиться с этой проблемой, но я уверен, что для этого было предложение по расширению языка, и я хочу его найти.