Отступ «где» в Haskell: почему он должен иметь отступ перед идентификатором? - PullRequest
21 голосов
/ 08 февраля 2010

Этот код:

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])

Сбой:

Прелюдия>: l safeListFs.hs
[1 из 1] Компиляция Main (safeListFs.hs, интерпретация)

safeListFs.hs: 9: 8: ошибка синтаксического анализа (возможно, неверный отступ)
Сбой, загруженные модули: нет.

Но эта версия:

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 из 1] Компиляция Main (safeListFs.hs, интерпретация)
Хорошо, модули загружены: Main.

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

Ответы [ 3 ]

30 голосов
/ 09 февраля 2010

По сути, Haskell отмечает столбец, где появляется первый непробельный символ после where (в данном случае c из convert), и обрабатывает следующие строки, начинающиеся в этом столбце, как новые определения внутри where.

Строка, которая продолжает определение предыдущей строки (например, ваши | охранники), должна иметь отступ справа от первого непробельного символа (c в вашем коде).

Строка с отступом слева от c будет за пределами where (например, начало вашей следующей функции верхнего уровня).

Это столбец первого символа, следующего за where, который имеет решающее значение, даже если он находится на новой строке:

  where
    convert acc x
      | ...
    anotherFunction x y

    ^ 
13 голосов
/ 08 февраля 2010

Вложенный контекст должен иметь больший отступ, чем окружающий контекст (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 = ...
6 голосов
/ 08 февраля 2010

Потому что вы всегда должны делать отступы в определениях функций. (В вашем случае все вещи, начатые в одном столбце в where, рассматриваются как определения "одного уровня").

...