GHCi中的多行命令


134

我在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


Answers:


183

大多数时候,您可以依靠类型推断来为您确定签名。在您的示例中,以下足够了:

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交互的更多信息。


1
非常感谢您提供的两种解决方案。但是我还有另一个相关问题:为什么第二行(在addTwo之前)需要四个前导空白?这必须是准确的,如果空白更少或更多,那么就会出现错误。
R71

9
@Rog let开始一个块;块中的条目按缩进分组;块中的第一个非空白字符设置缩进方式,以将它们分组。由于let上面块中的第一个非空白字符是aof addTwo,因此必须将块中的所有行缩进与该行一样深a
Daniel Wagner

谢谢。我还注意到在其他let / where块中。与其他忽略空格的语言相比,这是一个很大的区别,因此我在理解它方面有些困难。
R71

124

通过启动GHCI并输入:set +m以下命令来解决此问题:

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

繁荣。


这里发生的事情(并且我主要是在与聊天,在通过Learn Has a Haskell进行工作时谷歌搜索以寻求帮助)是GHCI是一个交互式环境,您可以在其中动态更改函数名称的绑定。您必须将函数定义包装在一个let块中,以便Haskell知道您将要定义一些内容。这些:set +m东西是多行:{ 代码 :}构造的简写。

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


5
如此简单,但并不明显。我想为我在第一页上没有告诉我的那本书而大叫!
蒂姆(Tim)

2
从Linux Shell,echo ':set +m' >> ~/.ghci使此设置持久化。
trueadjustr

您可以将let自己放在第一行,然后完全不需要缩进。空格真正起作用的地方是您的行上一定不能有尾随空格。尾随空格算作一个额外的Enter键,并中断多行块。
尼斯

14

用途let

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

4

GHCI版本8.0.1开始let不再需要在REPL上定义功能。

因此,这应该适合您:

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

Haskell的类型推断提供了适用于浮点数的通用类型:

λ: 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由于非多态输入而尝试传递除a以外的任何内容,则会出现错误:

λ: 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

2

至少要在GHCi 8.4.4版本中扩展Aaron Hall的答案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

但是:{:}技术确实如此。


1
实际上,甚至在以前,您都可以键入:{,然后单独输入下一行let,然后粘贴定义,不添加任何缩进,然后使用结束:}。:),并且在设置了多行输入模式(:set +m)的情况下,只要代码行上没有尾随空格,您甚至都不需要花括号命令。
尼斯

嗯,那么:set +m就可以随便使用let它吗?所以你可以-太酷了。谢谢。
大卫

嗯,我发现在某些情况下,简单地输入let然后换行符是行不通的。看到我的编辑。
davidA
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.