Какой отступ требуется для оператора case в операторе let?
Работая в хаскеле, нашел странное поведение, раздев его до голой кости
Это работает
a :: Bool
a = case True of
True -> True
False -> False
Но когда я пытаюсь
b :: IO Bool
b = do
let b' = case True of
True -> True
False -> False
return b'
я получил
ghci>:l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
test.hs:16:14: parse error on input ‘->’
Failed, modules loaded: none.
Так что я стараюсь
c :: IO Bool
c = do
let c' = case True of
True -> True
False -> False
return c'
И это работает.
Какие? Зачем? Зачем мне нужен дополнительный отступ в этом случае? Я ничего не могу найти по этому поводу, вероятно, потому что эти ключевые слова очень короткие и часто встречаются в повседневном языке. Есть какая-то спецификация, которая объясняет это поведение?
2 ответа
У меня нет точной формулировки из спецификации, но эта страница Wikibook объясняет проблему довольно четко.
Причина, по которой это работает так, проста: поддерживать связывание нескольких переменных с помощью одной группы let, например:
c = do
let c' = …
d = …
e = …
return c'
Ваш True -> …
а также False -> …
ошибочно интерпретируются как дополнительные переменные для привязки.
Основные правила отступов на самом деле довольно просты:
- после ключевых слов, которые начинают блок (
where
,let
,do
,case .. of
) запишите в столбце, где начинается следующее слово (которое может быть в следующей строке) - строки с отступом точно так же, как и новые записи в блоке
- строки с отступом больше, чем продолжение предыдущей записи
- строка с отступом меньше, чем заканчивает блок прямо перед этой строкой
- во вложенных блоках сначала примените правила к внешнему блоку
Хитрый пример:
1 + case x of
A -> 45 -- note where "A" starts
B -> 10 -- same indentation: another case branch
+ 2 -- more indented, so it's "10+2"
+ 10 -- less indented, so it's "1+(case ...)+10"
В твоем случае,
let b' = case True of
True -> True
False -> False
у нас есть два вложенных блока, один для let
и один для case..of
, let
блоки использует столбец b'
, case..of
Блок пытается повторно использовать тот же столбец, но сначала нам нужно применить правила к самому внешнему блоку. Итак True -> ...
линия на самом деле новая запись let
блок. Это вызывает ошибку разбора.