Haskell新手求助:如何定义列表的非平凡分割函数
问题分析
你的代码核心问题是递归时没有累积头部元素:处理(l:ls)时,你只生成了([l], ls)这个分割,然后直接拼接splits ls的结果,但splits ls返回的分割里,左半部分并没有把当前的l加进去,导致最终结果里每个元组的左半部分都是单个元素,而非逐步累积的子列表。
另外题目要求“非平凡分割”,通常指左右子列表都不为空,所以空列表的情况应该返回空列表,而非包含([],[])的平凡分割。
修正后的实现
splits :: [Int] -> [([Int],[Int])] splits [] = [] splits (x:xs) = ([x], xs) : map (\(a,b) -> (x:a, b)) (splits xs)
代码解释
- 递归基例:空列表没有非平凡分割,直接返回
[]。 - 递归步骤:
- 先生成当前列表的第一个非平凡分割:左半部分是
[x],右半部分是剩余的xs。 - 递归处理剩余列表
xs,得到xs的所有非平凡分割。 - 用
map把每个递归得到的分割(a,b)转换为(x:a, b)——这一步就是把当前头部元素x累积到左半部分的前面,生成更长的左子列表。
- 先生成当前列表的第一个非平凡分割:左半部分是
测试结果
对于输入[1,2,3,4],运行结果为:
[([1],[2,3,4]), ([1,2],[3,4]), ([1,2,3],[4])]
完全符合非平凡分割的要求:每个元组的左右子列表都不为空,且覆盖了所有可能的分割方式。
额外扩展(通用类型)
如果想让函数支持任意类型的列表,而非仅[Int],可以修改类型签名:
splits :: [a] -> [([a], [a])]
这样函数可以处理[Char]、[Bool]等任意列表类型,实用性更强。
内容的提问来源于stack exchange,提问作者SixtyFever
相关产品推荐
相关产品推荐

