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

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.

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

4b9b3361

Ответ 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, считаются "одинаковым уровнем" ).