使用reduce对多数字应用sum-of-squares得到错误结果的原因
问题成因
返回结果不符合预期的核心原因是对reduce的归约逻辑、自定义sum-of-squares函数的行为存在认知偏差:
- 你定义的
sum-of-squares是二元函数,逻辑为对传入的两个参数分别取平方后求和,它不会校验传入参数的类型或来源,只要传入就会先执行平方运算。 - Common Lisp中
reduce默认做左结合二元归约:处理长度大于2的列表时,会把上一次函数调用的返回值,和列表中下一个未处理的元素作为两个入参,再次传入目标函数迭代计算。
执行(reduce 'sum-of-squares '(2 2 2))的实际计算步骤为:
- 取列表前两个元素2、2传入函数:
(sum-of-squares 2 2) = 2² + 2² = 8 - 将上一步返回的8,和列表剩余的第三个元素2传入函数:
(sum-of-squares 8 2) = 8² + 2² = 64 + 4 = 68
前两个数的平方和结果8被再次平方,完全不符合「每个元素仅平方一次后累加」的预期,自然得不到12的结果。
正确写法
要计算列表所有元素的平方和,不要直接将sum-of-squares作为reduce的入参,应该先对列表内每个元素单独做平方映射,再通过加法做归约:
;; 定义平方函数 (defun square(x) (* x x)) (defun sum-of-squares (x y) (+ (square x) (square y))) ;; 先映射求每个元素的平方,再累加 (reduce #'+ (mapcar #'square '(2 2 2)))
上述代码执行后得到4+4+4=12,符合预期结果。
内容的提问来源于stack exchange,提问作者Wizard
相关产品推荐
相关产品推荐

