如何跨多行在ghci中定义函数?


161

我正在尝试定义ghci中跨越多行的任何简单函数,以以下示例为例:

let abs n | n >= 0 = n
          | otherwise = -n

到目前为止,我已经尝试过在第一行之后按Enter键:

Prelude> let abs n | n >= 0 = n
Prelude>           | otherwise = -n
<interactive>:1:0: parse error on input `|'

我也尝试过使用:{and :}命令,但距离并不远:

Prelude> :{
unknown command ':{'
use :? for help.

我在Linux上使用适用于Haskell 98的GHC Interactive版本6.6,我缺少什么?


20
请升级您的GHC安装。GHC 6.6已有5年的历史了!Haskell的最新版本在这里:haskell.org/platform
Don Stewart 2010年


1
@Mark此OP已尝试解决该问题的解决方案。此问题是由于ghci过期,而不是缺乏有关操作的知识所致。解决方案在这里:升级。解决方案:使用:{:}
AndrewC 2014年

Answers:


125

对于后卫(如您的示例),您可以将它们全部放在一行上,这样就可以工作(后卫不在乎间距)

let abs n | n >= 0 = n | otherwise = -n

如果要编写具有多个定义且参数匹配的定义的函数,如下所示:

fact 0 = 1
fact n = n * fact (n-1)

然后,您可以使用大括号和分号来分隔定义

let { fact 0 = 1 ; fact n = n * fact (n-1) }

258

GHCi现在具有多行输入模式,通过:set + m启用。例如,

Prelude> :set +m
Prelude> let fac 0 = 1
Prelude|     fac n = n * fac (n-1)
Prelude|
Prelude> fac 10
3628800

39
ghci在这方面,设置多行模式会使行为类似于Python解释器。很方便!实际上,您可以在.ghci主目录中创建一个文件,放置该文件后:set +m,多行模式将在每次启动时成为默认文件ghci
kqr

2
真的很棒 但是我注意到,当我使用:set prompt "λ "连续的行Prelude而不是来设置提示时λ。有什么办法解决这个问题?
abhillman 2014年

2
看到这里的补丁,以定义新的继续提示ghc.haskell.org/trac/ghc/ticket/7509#no1
karakfa 2014年

4
为了防止前奏出现在续行上,请在.ghci中也添加:set提示符2“ |”。
尼克

12
您可以完全避免使用尾随缩进let。只需键入a,let后跟换行符:let⏎。然后fac 0 = 1⏎。然后fac n = n * fac (n-1)⏎,您就完成了!
Iceland_jack

62

丹是正确的,但:{:}必须在每个出现在自己的行:

> :{ 
> let foo a b = a +
>           b
> :}
> :t foo
foo :: (Num a) => a -> a -> a

这也与布局规则交互,因此在使用do表示法时,显式使用花括号和分号可能会更容易。例如,此定义失败:

> :{
| let prRev = do
|   inp <- getLine
|   putStrLn $ reverse inp
| :}
<interactive>:1:18:
    The last statement in a 'do' construct must be an expression

但是在添加括号和分号时可以使用:

> :{
| let prRev = do {
|   inp <- getLine;
|   putStrLn $ reverse inp;
| }
| :}
> :t prRev
prRev :: IO ()

仅当从文件中粘贴定义(缩进可能会更改)时,这才真正重要。


如果行以'='结尾(下一行定义如下)(至少在7.6.3版中),则此方法无效。
AdamC 2014年

1
也许失败了,因为让行的第二行和第三行缩进得不够……?(还有两个空格。)
Evi1M4chine


7

如果您不想只为:{和升级GHC :},则需要全部写在一行上:

> let abs' n | n >= 0 = n | otherwise = -n

我不知道Haskell中的任何单一定义必须多行编写。以上确实适用于GHCi:

> :t abs'
abs' :: (Num a, Ord a) => a -> a

对于其他表达式,例如do块,您需要将非布局语法与花括号和分号(eugh)结合使用。


0

我正在macOS Catalina 10.15.2上使用GHCi版本8.2.1。以下是如何将函数类型声明和防护一起放在一起。请注意,左侧的竖线适用于GHCi多行。

λ: let abs' :: (Num a, Ord a) => a -> a
 |     abs' n | n >= 0 = n | otherwise = -n
 | 
λ: abs' 7
7
λ: abs' (-7)
7

1
如果您使用:{并且:}不需要let 在类型声明之前指定,则意味着您无需缩进第二行和后续行。
大卫

非常感谢davidA。那正是我一直在寻找但找不到的东西。
Golden Thumb

0

看起来像一次粘贴两条线,或者对每条新行使用control-enter都可以将它们保持在一起,至少在https://repl.it/languages/haskell处保持一致。您将在第二行的开头看到2个点。或将其放在文件中并:load文件(:l main)。Abs为何不适用于负数?哦,你必须在数字前后加上括号。

   let abs n | n >= 0 = n 
..           | otherwise = -n
   abs (-1)
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.