以addVat为例:接收函数为参数的高阶函数是否属于纯函数?
关于addVat是否为纯函数的解答
纯函数有两个核心判定标准:
- 相同的输入永远返回相同的输出结果
- 执行过程不会产生任何可观测的外部副作用(例如修改全局变量、IO操作、修改入参本身等)
核心结论:addVat本身是纯函数
传入不纯的getVat参数,只会让具体的调用过程变得不纯,而非addVat本身不纯。高阶函数的纯度判定看的是自身逻辑的纯度:只要传入的所有参数都是确定、无副作用的,addVat的返回值就唯一,且自身不会额外产生任何副作用,完全符合纯函数的定义。
你可以用大家最熟悉的高阶函数Array.map类比:map本身是公认的纯函数,如果你给它传入一个带副作用的回调(比如内部打日志、修改外部变量),整个调用过程会产生副作用,但不纯的来源是你传入的回调参数,而非map自身的逻辑。
对应你给出的示例可以很清晰看到不纯的来源:
- 传入返回随机值的
getVat时,调用结果不可预测的问题出在getVat本身的随机逻辑:
const getVat = ()=> Math.random() addVat('UK',getVat, 20)
- 产生数据库操作副作用的来源同样是
getVat,addVat自身没有执行任何修改外部状态的逻辑:
const getVat = ()=> { updateDbWithVatUsed(0.2) return 0.2 } addVat('UK',getVat, 20)
- 当传入纯的
getVat实现时,调用结果完全可预测,也符合单元测试的表现:
const getUKVat = ()=> 0.2 assert.equal(addVat('UK',getUkVat, 20), 24)
高阶函数纯度判定疑问解答
你提到的「纯函数的纯度定义是否要排除参数传入的外部调用行为」,答案是:我们判定高阶函数的纯度时,默认基于参数本身的纯度前提判定,不需要结合实际调用场景。
这个逻辑和普通函数完全一致:比如普通数值相加函数const add = (a,b) => a + b本身是纯函数,如果你给它传入一个每次读取都会变化的全局变量作为参数,导致调用结果不确定,你不会认为add本身不纯,问题出在参数上。高阶函数的判定规则没有特殊之处:只要自身逻辑不引入不确定性、不产生副作用,它本身就是纯的,和你实际传入什么参数没有关系。
内容的提问来源于stack exchange,提问作者Jose Marin
相关产品推荐
相关产品推荐

