Haskell "where" отступы: почему он должен быть отступом прошлого идентификатора?
Этот код:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input: not an int - " ++ [x])
Не удается:
Prelude> :l safeListFs.hs
[1 of 1] Compiling Main ( safeListFs.hs, interpreted )
safeListFs.hs:9:8: parse error (possibly incorrect indentation)
Failed, modules loaded: none.
Но эта версия:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input: not an int - " ++ [x])
нормально:
Prelude> :l safeListFs.hs
[1 of 1] Compiling Main ( safeListFs.hs, interpreted )
Ok, modules loaded: Main.
Я не могу понять, почему эти два последних отступа имеют значение.
Ответы
Ответ 1
В принципе, Haskell отмечает столбец, где первый непространственный символ после того, where
появляется (в данном случае, c
convert
), и обрабатывает следующие строки, начинающиеся в этом столбце, как новые определения внутри where
.
Линия, которая продолжает определение предыдущей строки (например, ваши |
охранниками) должны быть отступы справа от первого не символ пробела (c
в коде).
Линия с отступом слева c
будет вне where
(например, начало следующей функции верхнего уровня).
Это столбец первого символа следующий, where
это важно, даже если он на новой строке:
where
convert acc x
| ...
anotherFunction x y
^
Ответ 2
Вложенный контекст должен иметь дополнительный отступ, чем охватывающий контекст (n > m). Если нет, L терпит неудачу, и компилятор должен указать ошибку компоновки.
От http://www.haskell.org/onlinereport/syntax-iso.html.
Это также провалится:
import Data.Char (digitToInt)
myInt :: String -> Int
myInt [] = error "bad input: empty string"
myInt (x:xs)
| x == '-' = -1 * myInt xs
| otherwise = foldl convert 0 (x:xs)
where convert acc x
| x `elem` ['0'..'9'] = 10 * acc + digitToInt x
| otherwise = error ("bad input: not an int - " ++ [x])
Я плохо разбираюсь в вещах. Там есть новый контекст после ключевого слова where
, потому что вы можете указать несколько функций там - помните, что ваша программа начинается с неявного module Main where
, поэтому я думаю, что логично требовать, чтобы тело функции было отступом, как на (компилятор ожидает другого идентификатора в столбцах M и N, а тела декларации должны быть отступы).
fun = ...
^ where fun' = ...
M ^
N
fun'' = ...
fun2 = ...
Ответ 3
Потому что вы всегда должны указывать определения функций отступа.
(В вашем случае все вещи, начатые в одном столбце в where
, считаются "одинаковым уровнем" ).