В отчете Haskell есть несколько печально известное предложение в правилах макета, называемых «parse-error(t)». Цель этого правила состоит в том, чтобы не заставлять программиста писать фигурные скобки в однострочных выражениях let
и подобных ситуациях. Соответствующее предложение:Как компиляторы Haskell реализуют правило parse-error (t) на практике?
сторона состояние синтаксического анализа ошибок (т) следует интерпретировать следующим образом: если маркеры генерируется до сих пор L вместе со следующим маркером т представляют недопустимый префикс грамматики Haskell, и токены, сгенерированные до сих пор L, за которым следует токен "}", представляют собой действительный префикс грамматики Haskell, тогда parse-error (t) истинно.
Это создает необычную зависимость, где лексер обязательно и производит маркеры для синтаксического анализа и реагирует на ошибки, полученных в парсер, вставив дополнительные маркеры для парсер, чтобы потреблять. Это не похоже на то, что вы найдете в любом другом определении языка, и сильно усложняет реализацию, если оно интерпретируется буквально на 100%.
Неудивительно, что компилятор Haskell, о котором я знаю, реализует все правило в письменном виде. Например, GHC fails to parse the following expression, который является законным согласно отчету:
let x = 42 in x == 42 == True
Есть широкий спектр других подобных странных случаев. This post имеет список некоторых особенно трудных примеров. Некоторые из этих GHC работают правильно, но он также (по состоянию на 7.10.1) не будет работать на этой одном:
e = case 1 of 1 -> 1 :: Int + 1
Кроме того, он, кажется, GHC имеет расширение недокументированного языка называется AlternativeLayoutRule
, заменяющий разбор ошибка (т) с стеком контекста токенов в лексере, который дает аналогичные результаты в большинстве случаев; однако это не поведение по умолчанию.
Что делают компиляторы Haskell реального мира (в частности, GHC в частности), чтобы приблизить правило parse-error (t) во время lexing? Мне любопытно, потому что я пытаюсь реализовать простой компилятор Haskell, и это правило действительно отключает меня. (Смотри также this related question.)
Эти странные случаи, которые вы показываете, были отменены в Haskell 2010 именно потому, что они необоснованны для реализации. Обратите внимание, как эта публикация с 1999 года. –
На самом деле сейчас я не уверен во втором примере. Кажется, что он отключает GHC не потому, что он не обрабатывает синтаксический анализ, а потому, что существует расширение синтаксиса, которое делает '+' законным внутри типа ... –
Чтобы увидеть, что GHC на самом деле * пытается * правильно реализовать правило, обратите внимание, что 'case 1 of 1 -> 1 :: Int :: Int' отлично разбирается. –