在 GHC 8.6.5 中是否删除了在 do 块中使用 let 语句的能力?
Has the ability to use let statements in do blocks been removed in GHC 8.6.5?
我在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 }
不会产生此错误。
这个被删除了吗?如果是这样,我是否需要在 let in
表达式中添加第二个 do
块?
这里的问题是它也将您的 putStrLn b
解析为 let
声明,因此它基本上将其解析为:
do { a <- getLine; let <b>{ b = "Hello " ++ a ; putStrLn b }</b> }
因此它正在 putStrLn
部分中寻找 =
,您将在其中定义 putStrLn
函数。因此,解析器具有 "idea" 您正在定义一个函数,而不是调用一个函数。
的确,我们可以这样写例如:
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
的优先级取决于 Chapter 3: Expressions in the Haskell'10 report 中定义的语法。
let
是一个类似于 do
的布局关键字,既作为 do
块中的语句,又作为 let
…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 自然会在 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
到return到single-line模式。
我在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 }
不会产生此错误。
这个被删除了吗?如果是这样,我是否需要在 let in
表达式中添加第二个 do
块?
这里的问题是它也将您的 putStrLn b
解析为 let
声明,因此它基本上将其解析为:
do { a <- getLine; let <b>{ b = "Hello " ++ a ; putStrLn b }</b> }
因此它正在 putStrLn
部分中寻找 =
,您将在其中定义 putStrLn
函数。因此,解析器具有 "idea" 您正在定义一个函数,而不是调用一个函数。
的确,我们可以这样写例如:
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
的优先级取决于 Chapter 3: Expressions in the Haskell'10 report 中定义的语法。
let
是一个类似于 do
的布局关键字,既作为 do
块中的语句,又作为 let
…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 自然会在 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
到return到single-line模式。