GHCi中的缩进错误,实现filter

3
Prelude> let filter' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs
Prelude> let filter' _ [] = []
Prelude> filter' odd [1..10]
*** Exception: <interactive>:1:5-21: Non-exhaustive patterns in function filter'

我缺少什么模式?
Prelude> :{
Prelude| let filter' p (x:xs)
Prelude|     | p x              = x : filter' p xs
Prelude|     | otherwise        = filter' p xs
Prelude| let filter' _ []       = []
Prelude| :}

<interactive>:2:5: parse error (possibly incorrect indentation)

在ghci中定义这个(语法上)的惯用方法是什么? 在定义以下子句之前需要留下多少空间才能将等号=对齐?关于:{}: 有更好的方法吗?


1
请参见https://dev59.com/InE85IYBdhLWcg3wMAfc。 - sth
5个回答

10

这里有两个问题。第一个问题是使用多个 let 语句会产生两个不同的定义,后者会遮盖前者。第二个问题是语法错误的原因在于你没有对保护条件进行足够的缩进(| px ... 行应该比 filter' p (x:xs) 更进一步缩进)。

虽然将定义保留在文件中更简单,但以下是如何在 GHCi 中正确输入它的方法。

Prelude> :{
Prelude| let filter' p (x:xs)
Prelude|      | p x       = x : filter' p xs
Prelude|      | otherwise = filter' p xs
Prelude|     filter' _ [] = []
Prelude| :}

:{:}命令用于输入跨越多行的定义。对齐=是可选的,重要的是行的缩进。


4

不要在ghci提示符下编写函数 - 将它们保存在MyFunctions.hs或其他文件中,然后执行。

:l MyFunctions

在ghci中。

let命令会覆盖先前的定义,因此当您执行以下操作时:

let filter' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs
let filter' _ [] = []

你实际上正在执行的是let filter' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs,然后完全删除该定义,以替换为let filter' _ [] = []非穷举模式表示您在[1..10]上使用了filter'的第二个定义,而该列表不为空,您的filter'的第二个版本仅涵盖空列表!
您的定义很好,没有缩进错误,尽管filter'' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs很丑。我意识到你想在ghci中编写一行代码,但文本编辑器+ghci+http://www.haskell.org/hoogle/是一个强大的组合!

2
然后,输入 :r 以重新加载。 - m09

1
进一步解释Andrew的答案,请考虑以下ghci会话。
Prelude> let x = 1
Prelude> let x = 2
Prelude> x
2

那就是,在ghci中的let表达式引入了一个新变量并遮盖了旧定义。正如Andrew所建议的,只需将您的定义保存到文件中即可。

1
正如其他答案所指出的那样,每次在GHCi中有一个新的let语句时,它都会覆盖先前的定义。但是,您仍然可以通过将定义放入一个let语句中来使用模式匹配。基本上有两种方法可以做到这一点。
首先,只需使用分号:
let filter' p [] = []; filter' p (x:xs) | p x = x : filter' p xs | otherwise = filter' p xs

其次,使用:{ ... :}和缩进。
:{
let filter' _ [] = []
    filter' p (x:xs)
      | p x = x : filter' p xs
      | otherwise = filter' p xs
:}

(我省略了提示,以便更轻松地复制粘贴。)

0

除了 Hammar's answer 之外,你还可以设置 "允许多行命令":

Prelude> :set +m

您可以在不使用:{:}的情况下编写多行定义。 一个空行将结束一个块。
Prelude> let filter' p (x:xs)
Prelude|      | p x       = x : filter' p xs
Prelude|      | otherwise = filter' p xs
Prelude|     filter' _ [] = []
Prelude|
Prelude>

如果您想切换回单行模式,则运行unset:
Prelude> :unset +m

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接