GHCi 中的多行命令

在 ghci 中输入多行命令有问题。

以下两行代码从一个文件工作:

addTwo :: Int -> Int -> Int
addTwo x y = x + y

但当我输入 ghci 时,我得到一个错误:

<interactive>:1:1: error:
Variable not in scope: addTwo :: Int -> Int -> Int

我还尝试将代码放在 :{ ... :}中,但它们也不适用于此示例,因为这只是将代码行追加到一行中,这种情况不应该发生。

我正在使用 WinGHCi,版本2011.2.0.1

41274 次浏览

大多数情况下,您可以依靠类型推断为您生成签名。在你的例子中,以下内容就足够了:

Prelude> let addTwo x y = x + y

如果您确实想要一个具有类型签名的定义,或者您的定义跨越多行,那么可以使用 ghci:

Prelude> :{
Prelude| let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude| :}
Prelude> addTwo 4 7
11

请注意,您也可以将这个代码压缩到一行:

Prelude> let addTwo :: Int -> Int -> Int ; addTwo x y = x + y

您可以在文档的 在提示符下进行交互式评估部分找到有关与 ghci 交互的更多信息。

使用 let:

Prelude> :{
Prelude| let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude| :}
Prelude> addTwo 2 3
5

通过启动 GHCI 并键入 :set +m来解决这个问题:

Prelude> :set +m
Prelude> let addTwo :: Int -> Int -> Int
Prelude|     addTwo x y = x + y
Prelude|
Prelude> addTwo 1 3
4

砰。


这里发生了什么(我主要是在和 交谈,人们在通过 向你学习 Haskell工作的同时在谷歌上寻求帮助)是 GHCI 是一个交互式的环境,在这里你可以随时更改函数名的绑定。您必须将函数定义包装在 let块中,这样 Haskell 才知道您将要定义某些内容。:set +m是多行 :{ 密码 :}构建体的简写。

空格在块中也很重要,因此在类型定义之后,必须将函数定义缩进四个空格,以解释 let中的四个空格。

GHCI 版本8.0.1开始,不再需要 let在 REPL 上定义函数。

所以这对你来说应该没问题:

λ: addTwo x y = x + y
λ: addTwo 1 2
3
λ: :t addTwo
addTwo :: Num a => a -> a -> a

Haskell 的类型推断提供了适用于 float 的通用类型:

λ: addTwo 2.0 1.0
3.0

如果您必须提供您自己的输入,那么似乎您需要使用 let和多行输入相结合(使用 :set +m在 GHCI 中启用多行输入) :

λ: let addTwo :: Int -> Int -> Int
|     addTwo x y = x + y
|
λ: addTwo 1 2
3

但是,如果您尝试传递除 Int以外的任何内容,都会得到错误消息,因为您的输入是非多态的:

λ: addTwo 2.0 1.0


<interactive>:34:8: error:
• No instance for (Fractional Int) arising from the literal ‘2.0’
• In the first argument of ‘addTwo’, namely ‘2.0’
In the expression: addTwo 2.0 1.0
In an equation for ‘it’: it = addTwo 2.0 1.0

要在 Aaron Hall 的回答上展开,至少在 GHCi 8.4.4版本中,如果使用 :{ :}样式,则不需要将 let与类型声明一起使用。这意味着你不必担心在后面的每一行中添加4个空格的缩进来解释 let,使得更长的函数更容易输入,或者在很多情况下,复制粘贴(因为原始源代码可能不会有正确的缩进) :

λ: :{
| addTwo :: Int -> Int -> Int
| addTwo x y = x + y
| :}
λ: addTwo 1 2
3

更新

作为替代方案,您可以使用 :set +m打开多行输入模式,然后单独键入 let,按 Enter,然后粘贴定义,不需要缩进。

然而,这似乎并不适用于某些代码块,例如:

class Box a where
mkBox :: a -> Boxes.Box

但是 :{:}技术可以。