计算具有相同长度的连续子列表

Luk*_*gan 1 haskell

我试图计算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(前两个和后两个子列表具有相同的长度).

关于问题可能是什么线索?

谢谢

ehi*_*ird 6

在列表清单中只有一个元素那里是你不处理的情况下,所以你一旦遇到错误,正如你所说headxs,这将是[],因为有一个空列表中没有第一个元素:)

您可以使用模式匹配来解决此问题:

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时未定义除法.