Ошибка компилятора для программы Haskell не понята

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

Когда я компилирую, я получаю только одно сообщение об ошибке: «Ошибка синтаксического анализа (возможно, неправильный отступ или несоответствие скобок)»

Вот код без ошибок (printStmt) и очень похожий участок (VarDeclStmt) с ошибкой, направленной на чтение строки "expr >>= \s ->". Я не понимаю, почему один будет в порядке, а другой вызовет проблемы. Чем они отличаются?

printStmt = 
            keyword "print" >>
            expr >>= \e ->
            symbol ";" >>
            return (Print e)

varDeclStmt = do
              keyword "var" >>
              expr >>= \s -> --ERROR
              symbol "=" >>
              expr >>= \e ->
              return (VarDecl s e) 

person Matt Robbins    schedule 15.11.2017    source источник


Ответы (2)


Это проблема отступа. Блок

varDeclStmt = do
              keyword "var" >>
              expr >>= \s -> --ERROR
              symbol "=" >>
              expr >>= \e ->
              return (VarDecl s e) 

разбирает как

varDeclStmt = do
              { keyword "var" >>
              ; expr >>= \s -> --ERROR
              ; symbol "=" >>
              ; expr >>= \e ->
              ; return (VarDecl s e) 
              }

что ерунда, так как первая запись keyword "var" >> недействительна.

Обратите внимание, что дальнейший (или меньший) отступ всего блока не меняет его синтаксический анализ.

Самое простое решение — полностью удалить do, чтобы текст под ним не анализировался как блок, следовательно, он не разбивался на отдельные записи, а анализировался, как если бы он был в одной строке.

В противном случае вы можете переключиться на правильную нотацию do

varDeclStmt = do
              keyword "var"
              s <- expr
              symbol "="
              e <- expr
              return (VarDecl s e) 

или (худшее решение) сделать блок do однократным, сделав отступ блока больше, чем первая строка, как показано ниже.

varDeclStmt = do
              keyword "var" >>
                expr >>= \s ->
                symbol "=" >>
                expr >>= \e ->
                return (VarDecl s e) 

Приведенное выше решение глупо, поскольку цель do состоит в том, чтобы разбить блок на записи, а отступ сделан так, чтобы была только одна запись. Итак, мы используем две вещи, чтобы противодействовать друг другу.

person chi    schedule 15.11.2017

Ошибка отступа связана с блоком do. Попробуйте сделать отступ после do. Что-то типа:

varDeclStmt = do
                keyword "var" >>
                expr >>= \s -> 
                symbol "=" >>
                expr >>= \e ->
                return (VarDecl s e)

Дай мне знать, если это работает.

person zale    schedule 15.11.2017
comment
Также стоит отметить, что ключевое слово do здесь не нужно, поскольку на самом деле do-нотация не используется. - person David Young; 15.11.2017
comment
Это не сработает: правило отступа сравнивает отступ первого слова после do с отступом следующих строк. Отступ do относительно блока не учитывается. Тем не менее, удаление do — это самое простое решение. - person chi; 15.11.2017