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

我尝试在 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 `|'

我也尝试过使用 :{:}命令,但没有取得进展:

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

我正在 Linux 上使用 GHC Interactive version 6.6 for Haskell 98,我错过了什么?

80636 次浏览

看起来 :{:}是一个相当新的特性。您可能需要升级 GHC。

编辑: 确认,见 http://www.haskell.org/ghc/docs/6.8.2/html/users_guide/release-6-8-2.html

如果你不想仅仅为 :{:}升级 GHC,你需要把它们写在一行:

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

我不知道在哈斯克尔有没有一个单一的定义说 必须的是写在多行上的。上述措施确实在 GHCi 中起作用:

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

对于其他表达式,比如 do块,需要使用带大括号和分号的非布局语法。

对于守卫(就像你的例子) ,你可以把他们放在一条线上,它的工作(守卫不关心间距)

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) }

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

> :{
> 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 ()

这只有在粘贴文件中的定义时才真正重要,因为缩进可能会发生变化。

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

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

我使用的是 GHCi,MacOSCatalina10.15.2版本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

这看起来像是一次粘贴两行或者使用控制输入为每个新的行保持它们在一起,至少在 https://repl.it/languages/haskell。你会在第二行的开头看到两个点。或者将其放入一个文件中,然后: 加载该文件(: l main)。为什么腹肌对负数不起作用?你得在数字前面加上括号。

   let abs n | n >= 0 = n
..           | otherwise = -n
   abs (-1)