Оператор делает отступ

hindent изменил мой код на:

do download i inputFile
   onException
     (callProcess (List.head args) (List.tail args))
     (removeFileIfExists name)
   `finally` removeFileIfExists inputFile

Я не могу определить, если finally относится к остальной части do блок или просто начало государства onException, Согласно этому,

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

Я не уверен, применяется ли это правило здесь.

Ли `finally` применить к остальной части до или только к последнему утверждению и почему?

2 ответа

Решение

Мы можем узнать, используя GHCi: написание

Prelude> let f = (>>)
Prelude> :{
Prelude| do print 5
Prelude|    print 4
Prelude|    `f` print 3
Prelude|    print 2
Prelude| :}

вызывает следующую ошибку типа (не ошибка разбора!)

<interactive>:12:8: error:
    • Couldn't match expected type ‘(() -> IO ()) -> Integer -> IO b’
                  with actual type ‘IO ()’
    • The function ‘print’ is applied to three arguments,
      but its type ‘Integer -> IO ()’ has only one
      In the second argument of ‘f’, namely ‘print 3 print 2’
      In the expression:
        do { print 5;
             print 4 }
        `f` print 3 print 2

Глядя на строки списка, мы обнаруживаем, как GHCi анализировал код, который печатается с явными скобками и точками с запятой.

Там мы видим, что `f` часть закрыла do блок! Это делает целое do блок, чтобы быть первым аргументом f, Далее, следующие строки, которые больше не находятся в блоке, теперь образуют одно выражение print 4 print 2 который используется в качестве второго аргумента для f, Это вызывает ошибку типа, так как она вызывает print с тремя аргументами.

Действительно, скобка } был вставлен до `f` из-за правила, указанного в OP: когда что-то не анализируется в блоке, мы добавляем } и продолжай.

Подводя итог, если `f` больше отступ, блок анализируется как

do print 5
   print 4 `f` print 3
   print 2

Если `f` отступ с предыдущей строкой или менее, блок анализируется как

(do { print 5
    ; print 4 }) `f` print 3 print 2

Я бы предложил избежать отступов `f` точно так же, как и в предыдущей строке: лучше сделать отступ меньше, чтобы синтаксический анализ стал очевидным даже для читателя.

Следующее на самом деле не адрес вашего кода, но вопрос, который вы, похоже, задавали. Вместо этого он адресует следующий код:

do download i inputFile
   onException
     (callProcess (List.head args) (List.tail args))
     (removeFileIfExists name)
   ░`finally` removeFileIfExists inputFile

ответ Чи адресует фактически отправленный код, с `finally` не отступать дальше download а также onException, Я бы заметил, что это плохой стиль: при написании этого обязательно делайте отступ меньше, т.е.

  do download i inputFile
     onException
       (callProcess (List.head args) (List.tail args))
       (removeFileIfExists name)
 `finally` removeFileIfExists inputFile

Как прокомментировал Виллем Ван Онсем, функциональные приложения всегда имеют приоритет перед инфиксными приложениями. Это верно для обоих "настоящих инфиксных операторов", таких как + или же >>=и для backtick-инфиксов... если факт не различается между этими типами операторов в отношении приоритета: для всех инфиксов приоритет определяется декларацией фиксированности, такой как

 infixl 6 +
infix 4 `elem`

Фиксированностью является число в диапазоне 0,9, а фиксированность может быть как левой, правой, так и неассоциативной. Если исправление не объявлено (как в большинстве именованных функций, тогда как для символьных инфиксов настоятельно рекомендуется дать объявление исправления), по умолчанию infixl 9 используется, то есть, в основном, самая высокая юридическая фиксация, которую вы можете назначить вручную.

ОТО, функция приложения всегда infixl 10 как бы то есть, то есть он связывается сильнее любого инфикса, независимо от того, как он объявлен. Итак, ваш пример разбирается как

do (download i inputFile)
   (  (onException
        (callProcess (List.head args) (List.tail args))
        (removeFileIfExists name))
    `finally`
      (removeFileIfExists inputFile) )
Другие вопросы по тегам