Расширение Haskell для синтаксиса отступов функций

#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 с древовидной структурой была бы простой, но я вообще не смог найти ни одного ресурса.

  1. Как называется эта концепция (и оператор, который я вызвал $$ )?
  2. Есть ли уже расширение GHC для этого?
    • Если нет, я был бы очень признателен за ссылки на любое другое связанное расширение. Я готов узнать, как написать расширение GHC для реализации этого.

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

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

 example = mappend
    [ lorem ipsum
    , dolor amet
    ]
  

они предпочитают объявлять экземпляр монады и писать

 example = do
    lorem ipsum
    dolor amet
  

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

Комментарии:

1. Неясно, зачем нужны и расширение, и оператор.

2. Вам нужны как расширение, так и оператор, потому что в противном случае вы не сможете добавить код нового стиля в существующий код старого стиля. Если нет нового оператора, включение расширения сделает antb c always mean a (b c) и never a 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 смог справиться с этой проблемой, но я уверен, что для этого было предложение по расширению языка, и я хочу его найти.