2

我在 中输入了一些代码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

4

2 回答 2

7

let是一个类似于 的布局关键字do,既可以作为do块中的语句,也可以作为let...<code>in... 表达式中的语句,因为它引入了绑定。这个:

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

对此进行脱糖:

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

而您所写的内容等同于:

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

所以很自然,GHC 期待别的东西——一个模式或=——after putStrLn b,因为你可以定义一个名为的局部函数putStrLn,其参数名为blet解决方案是在语句中使用显式大括号:

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返回单线模式。

于 2019-06-05T08:42:30.127 回答
4

问题在于它也将您解析putStrLn blet声明,因此它基本上将其解析为:

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

=因此,它在零件中寻找 a putStrLn,您将在其中定义putStrLn函数。因此,解析器具有您定义函数而不是调用函数的“想法”。

事实上,我们可以写例如:

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

所以这里我们在同一行声明了两个变量。

您可以使用大括号来明确let范围为 only b,例如:

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

的优先级let是由于语法,在第 3 章:Haskell'10 报告中的表达式定义。

于 2019-06-05T08:35:07.627 回答