存在一些语法问题以及类型问题。第一行看起来像:
contaOcs [] = [_,_]
但结果中的下划线 (_) 没有任何意义,您只能构造其中包含值的列表。当我们统计一个空列表的出现次数时,结果会是一个空列表,所以contaOcs [] = []。
至于第二个:
contaOcs [x] = [1,x]
在这里,您的目标是返回一个包含两个元素的列表:1 和 x(即 String)。在 Haskell 中,列表的元素都具有 same 类型。您可以做的是返回一个 2 元组列表,其中第一项为 Int,第二项为 String,就像签名所暗示的那样,但是您需要将值包装在一个 2 元组中,例如 @ 987654330@.
在你的最后一个子句中,你写:
contaOcs (i, x1:x2:xs) = ...
这没有多大意义:输入类型是一个列表(这里是 Strings),而不是带有 Int 的 2 元组和字符串列表。
所以输入看起来像:
contaOcs (x1:x2:xs) = ...
像(i+1,(x2:xs)) 这样的输出也不与签名中建议的输出类型“和谐”,这看起来像一个带有Int 和Strings 列表的二元组,所以@ 987654338@,不是[(Int, String)]。
基于上面的 cmets,我们推导出了类似的东西:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:x2:xs)
| x1 == x2 = -- ...
| otherwise = -- ...
所以现在有两部分要填写。如果x1 和x2 不 相等,这意味着我们可以首先在列表中产生一个元组(1, x1),然后由列表其余部分中contaOcs 的结果(包括x2),所以:
(1, x1) : contaOcs (x2:xs)
在后一种情况下,这意味着我们首先使用(x2:xs) 递归调用contaOcs,然后递增该列表第一项的计数器。我们确信这样的元素存在,因为我们使用包含至少一个元素的列表进行递归调用,并且通过归纳,这意味着结果也至少包含一个元素,因为基本情况包含一个元素,递归情况要么将元素添加到结果中,要么更新这些。
所以我们可以使用模式保护,并操纵结果,例如:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:x2:xs)
| x1 == x2, ((yi, yv):ys) <- contaOcs (x2:xs) = (yi+1, yv) : ys
| otherwise = (1, x1) : contaOcs (x2:xs)
我们也可以使用“as-pattern”:我们只需要引用以x2开头的列表尾部,而不是xs:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:xs@(x2:_))
| x1 == x2, ((yi, yv):ys) <- contaOcs xs = (yi+1, yv) : ys
| otherwise = (1, x1) : contaOcs xs
然而,上面的内容不是很优雅。在这里使用 累加器 可能会更好,我将其留作练习。