为什么Haskell自定义dropR函数使用drop n而非drop(n-1)才能正常工作
问题原因拆解
- 首先你的核心思路完全正确:从列表右侧删除n个元素的基础实现逻辑就是先反转列表、调用标准
drop删除n个元素、再反转回来,对应简化的非递归实现可以直接写成:
dropR :: Int -> [a] -> [a] dropR n xs = reverse . drop n $ reverse xs
- 你最初版本出错的原因:
你在dropR n (x:xs)分支中计算的reverse xs ++ [x],本质上就是完整的reverse (x:xs)(也就是整个输入列表的反转结果),此时你本应该直接传入n给drop删除对应数量的元素,却错误的传入了n-1,相当于少删了1个元素。
以你测试的dropR 2 [1,2,3,4,5]为例:
- 完整反转后的列表是
[5,4,3,2,1] - 你调用
drop 1得到的结果是[4,3,2,1],再次反转就是你得到的错误结果[1,2,3,4] - 改为
drop 2后得到[3,2,1],再次反转就是预期的[1,2,3]
- 关于
drop用n-1而你改对后的版本不用的疑问:
标准drop的n-1是递归逻辑的要求:每递归一次就剥掉列表的一个头元素,要删除的数量对应减1。
但你写的dropR递归分支本身并没有调用dropR做递归,你是直接把完整反转后的列表传给了标准drop处理,不需要自己做n的递减,直接传入原始要删除的数量n即可。你写的版本里的前三个边界分支实际上都被第四分支的逻辑覆盖,属于冗余代码。
内容的提问来源于stack exchange,提问作者Lumnar
相关产品推荐
相关产品推荐

