Haskell 在特定整数的实例上拆分列表

Haskell 在特定整数的实例上拆分列表,haskell,Haskell,我正在尝试编写一个函数,将一个特定整数的实例上的列表拆分为几个单独的列表。例如: splitlist[3,4,0,6,0,7]0将返回[[3,4]、[6]、[7]] 到目前为止,我已经: splitlist :: [Int] -> Int -> [[Int]] splitlist xs n | length xs == 0 = [] | head xs == n = [head (tail xs)] : splitlist (tail xs) n | otherwis

我正在尝试编写一个函数,将一个特定整数的实例上的列表拆分为几个单独的列表。例如:

splitlist[3,4,0,6,0,7]0
将返回
[[3,4]、[6]、[7]]

到目前为止,我已经:

splitlist :: [Int] -> Int -> [[Int]]
splitlist xs n 
  | length xs == 0 = []
  | head xs == n = [head (tail xs)] : splitlist (tail xs) n 
  | otherwise = [head xs : splitlist (tail xs) n] 
但是,我在第5行得到了头xs的类型错误:

    • Couldn't match type ‘[Int]’ with ‘Int’
      Expected type: [Int]
        Actual type: [[Int]]
    • In the second argument of ‘(:)’, namely ‘splitlist (tail xs) n’
      In the expression: head xs : splitlist (tail xs) n
      In the expression: [head xs : splitlist (tail xs) n]
  |
5 |   | otherwise = [head xs : splitlist (tail xs) n]
  |                            ^^^^^^^^^^^^^^^^^^^^^

我做错了什么?

xs
有类型
[Int]
,所以
头xs
有类型
Int
<代码>拆分列表具有类型
[Int]->Int->[[Int]]]
,因此
拆分列表(尾部xs)n
具有类型
[[Int]]
。您试图对这些值调用
,其类型为
a->[a]->[a]
。问题是,没有选择
a
就可以解决这个问题:如果你为
a
选择
Int
,那么它是错误的,因为第二个参数是
[[Int]]
而不是
[Int]
,如果你为
a
选择
[Int]
,那么它就错了,那么它就错了,因为第一个参数是
Int
,而不是
[Int]

我想你是想写
[head-xs]:splitlist(tail-xs)n
而不是
[head-xs:splitlist(tail-xs)n]
,就像上面那行一样。但是,尽管此类型进行了检查,但仍然不起作用(它会在测试用例上生成
[[3]、[4]、[6]、[6]、[7]、[7]
,以及
拆分列表[0]0
底部)

要真正修复它,首先让我们重写它,使其看起来更地道:

splitlist :: [Int] -> Int -> [[Int]]
splitlist [] _ = []
splitlist (x:xs) n
  | x == n = [head xs] : splitlist xs n
  | otherwise = [x] : splitlist xs n
我所做的改变是,我使用模式匹配来代替测试
长度
,然后使用
头部
尾部
。现在,逻辑问题变得显而易见:

  • 如果列表的最后一个元素是分隔符,则它将降到底部
  • 结果始终是一个仅包含单个元素列表的列表
  • 对于输入中的每个
    Int
    ,输出中总是有一个
    Int

我想这是一种练习,所以我不会破坏最后的答案。但是,这应该足以让您再次尝试。

作为一般建议,当模式匹配就足够时,使用
长度、头部、尾部
被认为是一种不好的做法。在最坏的情况下,你会得到一个崩溃的程序,就像上面的一个:为什么
head(tailxs)
在一个非空列表上会成功?通常,您会得到一个效率低下的程序:
length xs==0
扫描整个列表以计算其元素,但没有必要这样做。这是否回答了您的问题?谢谢我之所以尝试使用
[head-xs:splitlist(tail-xs)n]
是因为我试图解决您指出的第二个问题,即它始终是一个仅包含单个元素列表的列表。我仍然不知道该怎么做——我试图将x作为列表的第一个元素,然后再次调用该函数,但是我仍然得到类型错误,我不太确定如何避免。我也尝试过使用++,但我认为在模式匹配中不允许这样做。