Была ли удалена возможность использовать операторы let в блоках do в GHC 8.6.5? - PullRequest
2 голосов
/ 05 июня 2019

Я ввел некоторый код в ghci, похожий на этот:

main = do { a <- getLine ; let b = "Hello " ++ a ; putStrLn b }

Однако я получаю эту ошибку:

<interactive>:1:63: error: parse error on input `}'

В предыдущих версиях Haskell / GHC, я помню, это работало просто отлично - даже было прямо сказано, что в do блоках вам не нужно ключевое слово in. Тем не менее, единственный способ заставить это работать:

main = do { a <- getLine ; let b = "Hello " ++ a in putStrLn b }

, которая не выдает эту ошибку.

Это было удалено? Если да, нужен ли второй do блок внутри выражения let in?

Ответы [ 2 ]

7 голосов
/ 05 июня 2019

let - это ключевое слово макета, подобное do, как в выражении в блоке do, так и в выражении letin…, поскольку оно вводит блок из привязок. Это:

main = do
  a <- getLine
  let b = "Hello " ++ a
  putStrLn b

Desugars к этому:

main = do {
  a <- getLine;
  let {
    b = "Hello " ++ a;
  };
  putStrLn b;
};

В то время как то, что вы написали, эквивалентно этому:

main = do {
  a <- getLine;
  let {
    b = "Hello " ++ a;
    putStrLn b
  };
};

Поэтому, естественно, GHC ожидает чего-то другого - шаблона или = - после putStrLn b, поскольку вы могли бы определять локальную функцию с именем putStrLn с параметром с именем b. Решением является либо использование явных скобок в операторе let:

main = do { a <- getLine; let { b = "Hello " ++ a }; putStrLn b }

Или использовать многострочный режим в GHCi либо командой :{, завершенной командой :}:

> :{
| main = do
|   a <- getLine
|   let b = "Hello " ++ a
|   putStrLn b
| :}
>

Или с :set +m и завершается пустой строкой:

> :set +m
| main = do
|   a <- getLine
|   let b = "Hello " ++ a
|   putStrLn b
|
>

Затем следует :unset +m для возврата в однострочный режим.

4 голосов
/ 05 июня 2019

Проблема здесь в том, что он анализирует вашу putStrLn b как декларацию let, поэтому он в основном анализирует ее как:

do { a <- getLine; let <b>{ b = "Hello " ++ a ; putStrLn b }</b> }

Таким образом, он ищет = вputStrLn часть, где вы будете определять функцию putStrLn.Таким образом, у синтаксического анализатора есть «идея», что вы определяете функцию, а не вызываете ее.

Действительно, мы можем написать, например:

Prelude> let a = 3; f b = b + 1
Prelude> f a
4

, поэтому здесь мы объявили две переменные вта же строка.

Вы можете использовать фигурные скобки, чтобы указать, что let ограничен только b, например:

do { a <- getLine; let <b>{ b = "Hello " ++ a }</b>; putStrLn b }

Приоритет let обусловленк грамматике, определенной в Глава 3: Выражения в отчете Haskell'10 .

...