Haskell中iter函数实现里id函数的作用与运行逻辑疑问
关于Haskell iter函数中id作用的通俗解释
先明确基础概念
id是Haskell的内置恒等函数,定义为id x = x,作用是接收任何参数,原样返回- 函数组合运算符
(.)的规则:(f . g) x = f (g x),也就是把两个函数串起来,先执行右边的,再执行左边的 iter n f的功能是把函数f连续迭代应用n次,比如iter 3 (+1)等价于\x -> x + 3
递归版本iter的执行拆解(以n=3, f=(+1)为例)
我们一步步展开递归调用的过程:
-- 递归边界:n=0时直接返回id iter 0 (+1) = id -- n=1时,等于f 组合 iter 0 f iter 1 (+1) = (+1) . iter 0 (+1) = (+1) . id -- n=2时 iter 2 (+1) = (+1) . iter 1 (+1) = (+1) . (+1) . id -- n=3时 iter 3 (+1) = (+1) . iter 2 (+1) = (+1) . (+1) . (+1) . id
现在我们调用iter 3 (+1) 5,执行顺序是从右往左的:
(+1) ((+1) ((+1) (id 5))) -- 先算id 5 = 5,然后依次加1,最终得到8
这里id的作用就是处理迭代0次的边界情况:迭代0次f等价于什么都不做,返回输入本身,正好是id的功能。你可以把它理解为函数组合的"默认占位符",就像加法里的0,加了不会影响最终结果,但是能让边界情况的逻辑和普通递归逻辑统一。
foldr版本iter'的执行拆解
iter' n = foldr (.) id . replicate n的执行分两步:
- 先执行
replicate n f:把函数f复制n次,得到列表。比如n=3, f=(+1)时,得到[(+1), (+1), (+1)] - 对上述列表执行
foldr (.) id:foldr是从右往左折叠列表,初始值为id,折叠操作是函数组合(.)
对[(+1), (+1), (+1)]做foldr的展开结果和递归版本完全一致:
foldr (.) id [(+1), (+1), (+1)] = (+1) . ((+1) . ((+1) . id))
调用时的执行逻辑和递归版本没有任何区别,id同样是作为折叠的初始占位符,保证迭代0次(n=0时replicate得到空列表,foldr直接返回初始值id)的逻辑正确。
补充验证
如果把id换成其他函数比如(\x -> x + 100),你就会发现iter 0 (+1) 5会返回105,这和"迭代0次f应该返回原数"的预期完全不符,也就能直观感受到id的作用了。
内容的提问来源于stack exchange,提问作者Quin
相关产品推荐
相关产品推荐

