Подтвердить что ты не робот

Недоумевает, как этот код обрабатывается средством Haskell Layout

Во время просмотра https://wiki.haskell.org/IO_inside я столкнулся со следующим комментарием и кодом...

"Кроме того, правила макета Haskell позволяют использовать следующий макет:

main = do a <- readLn
          if (a>=0) then return ()
            else do
          print "a is negative"
          ...

который может быть полезен для выхода из середины длинного заявления do.

В дальнейшем я буду использовать символ C * для ссылки на приведенный выше код.

Я предполагаю, что намерение C * читать в числе, а затем:
(i) Если это неотрицательно, ничего не делайте.
(ii) Если он отрицательный, отобразите вывод, указав, что он есть.

Моя первоначальная реакция заключалась в том, чтобы думать, что C * не будет правильно анализировать или не будет вести себя так, как ожидалось.

Я думал, что Layout будет вставлять пустой набор фигурных скобок и точку с запятой сразу после второго "do", потому что "print" lexeme не имеет отступов больше, чем уровень отступов текущего контекста макета, установленного "a" в "a < - readLn".

То есть, мое предсказание для нечувствительного к макету кода (далее называемого C), сгенерированного макетом, будет выглядеть примерно так:

main = do {
          a <- readLn;
          if (a>=0) then return ()
            else do {};
          print "a is negative"
          ...
          }

Что я думал, что это так, было основано на следующем предложении, содержащемся в разделе 2.7 ( "Лексическая структура": "Макет" ) части 1 отчета о языке Haskell 2010 (https://www.haskell.org/onlinereport/haskell2010/haskellpa1.html):

"Если отступ непересекающейся лексемы сразу после того, где, пусть, do или из меньше или равно текущему уровню отступа, вместо того, чтобы начинать макет, вставляется пустой список" {} ", и обработка компоновки происходит для текущего уровня (т.е. вставка точки с запятой или замыкания).

Более подробный отчет о правилах макета приведен в разделе 10.3 ( "Ссылка на синтаксис": "Макет" ) части 1 (указанный выше URL) отчета о языке Haskell 2010.

При чтении этой более подробной учетной записи, я чувствовал себя уверенным, что мое предсказание для нечувствительного к макетам кода, сгенерированного макетом (то есть C '), было правильным.

Однако, к моему удивлению, когда я попробовал исходный код, описанный выше (т.е. C *) в GHCi, он работал (правильно разбирался и вел себя так, как ожидалось).

Вопросы...

  • Является ли приведенное выше предложение (из раздела 2.7) точным?

  • Является ли подробная информация о правилах макета, упомянутых выше (из раздела 10.3) точными?

  • Каковы недостатки в рассуждениях, которые я использовал для получения моего предсказания для нечувствительного к макетам кода (то есть C '), сгенерированного макетом для исходного кода C *?

  • Что представляет собой нечувствительный к макету код, созданный макетом для исходного кода, описанного выше (т.е. для C *), и каковы правила/принципы, которые его объясняют?

  • В общем, есть ли способ, чтобы я мог видеть нечувствительный к макету код, созданный макетом? Если да, то что это (пожалуйста, подробно или объясните технику на уровне, подходящем для кого-то нового для Haskell, как и я)?

4b9b3361

Ответ 1

Это известное и документированное отклонение GHC от стандартного Haskell в режиме по умолчанию или Haskell 98.

GHC имеет расширение языка, называемое NondecreasingIndentation, которое может использоваться для запуска этого поведения. Если включено, ключевое слово do вводит новый блок, даже если следующий токен начинается с того же уровня отступов, что и окружающий блок.

Если вы этого не хотите, скажите либо -XNoNondecreasingIndentation, либо -XHaskell2010 (или используйте языковые прагмы соответственно).

Вы можете просмотреть довольно печатную версию кода, обработанного GHC, передав флаг -ddump-parsed в GHC. Это только частично удалит макет (он делает это для do-блоков, но, например, не для let), но может все еще предоставлять подсказки.