我试图计算n和n + 1长度相同的列表元素.
我写了这段代码:
countSec :: [[Integer]] -> Integer
countSec (x:xs) = if (length x)==(length (head xs))
then 1+(countSec xs)
else (countSec xs)
countSec [] = 0
Run Code Online (Sandbox Code Playgroud)
你可能猜到,它不起作用.事实上,作为输出我得到" *异常:Prelude.head:空列表"
countSec [[1,2][1,2],[2],[3,5],[2],[5]] 应返回2(前两个和后两个子列表具有相同的长度).
关于问题可能是什么线索?
谢谢
在列表清单中只有一个元素那里是你不处理的情况下,所以你一旦遇到错误,正如你所说head的xs,这将是[],因为有一个空列表中没有第一个元素:)
您可以使用模式匹配来解决此问题:
countSec :: [[Integer]] -> Integer
countSec [] = 0
countSec [_] = 0
countSec (x : xs@(y:_))
| length x == length y = 1 + countSec xs
| otherwise = countSec xs
Run Code Online (Sandbox Code Playgroud)
我使用模式匹配来一次匹配列表中的两个元素.这就像x:(y:_)(模式可以嵌套),除了我们还给xs我们匹配的东西命名y:_; 所以我们有
xs
x y _____\_____
\ \ \
[1] : ([2, 3] : ...)
Run Code Online (Sandbox Code Playgroud)
x是列表的第一个元素,y是第二个元素,是第一个元素之后的列表xs.我们可以匹配(x:y:xs)并使用countSec (y:xs)递归,但这会占用更多内存并且更容易出错.
在_一个模式意味着我们不关心该位置上的价值,所以不想给它一个名字; 这是一个匹配一切的通配符.
作为一个小风格的笔记,我也将你的if表情转化为一个守卫; 这些基本上只是在函数子句级别的表达式.
你应该避免使用部分1函数,比如head模式匹配会因为这样的事情而起作用 - 它们会隐藏错误并使代码更难以阅读.我还建议将-Wall标志交给GHC; 如果你countSec像我一样写但却忘了零或单元素的情况,GHC会警告你:
Warning: Pattern match(es) are non-exhaustive
In an equation for `countSec': Patterns not matched: [_]
Run Code Online (Sandbox Code Playgroud)
1未为其所有输入定义的功能; 例如,head并且tail未定义[],并且除数为0时未定义除法.