Haskell递归求约数函数recdiv的执行逻辑理解疑问
recdiv函数逻辑讲解
首先明确recdiv三个入参的作用:
- 第一个参数
x:已做绝对值处理的、待求解约数的目标正整数 - 第二个参数
numlist:尚未完成整除校验的候选数字列表 - 第三个参数
divisors:已经校验完成、收集到的约数结果列表
接下来逐行解释守卫逻辑:
- 第一个守卫
| numlist == [] = divisors是递归终止条件:当所有候选数字都校验完成后,直接返回已收集到的约数列表。 - 第二个守卫
| mod x (last numlist) == 0 = recdiv x (init numlist) ((last numlist):divisors):- 先取当前候选列表的最后一个元素(也就是当前未校验的最大候选数),判断它是否能整除
x - 如果满足整除条件,说明该数是
x的约数:递归继续校验剩下的候选数(init numlist即去掉最后一个元素的剩余列表),同时把刚找到的约数插入到结果列表的头部
- 先取当前候选列表的最后一个元素(也就是当前未校验的最大候选数),判断它是否能整除
- 第三个守卫
| otherwise = recdiv x (init numlist) divisors:如果当前校验的候选数不能整除x,直接跳过该数,递归校验剩余的候选数,结果列表保持不变。
执行流程示例
以调用divides 6为例,实际触发的递归流程如下:
- 初始调用:
recdiv 6 [1,2,3,4,5,6] [] - 校验最后一位6:能整除6,递归调用
recdiv 6 [1,2,3,4,5] [6] - 校验最后一位5:不能整除6,递归调用
recdiv 6 [1,2,3,4] [6] - 校验最后一位4:不能整除6,递归调用
recdiv 6 [1,2,3] [6] - 校验最后一位3:能整除6,递归调用
recdiv 6 [1,2] [3,6] - 校验最后一位2:能整除6,递归调用
recdiv 6 [1] [2,3,6] - 校验最后一位1:能整除6,递归调用
recdiv 6 [] [1,2,3,6] - 候选列表为空,返回结果
[1,2,3,6]
该实现的逻辑是从大到小遍历所有候选数,找到的约数插入结果列表头部,最终返回的约数列表天然是升序排列的。
内容的提问来源于stack exchange,提问作者Quin
相关产品推荐
相关产品推荐

