ANSI Common Lisp 6.6节compose函数的正确递归实现方式
递归版compose的问题定位与实现
错误原因
你写的实现核心bug在递归分支的参数传递:
当fns非空时,代码里的(funcall fn (apply #'rec-compose fns)),调用rec-compose fns生成的是一个等待接收实参的闭包,但你没有把外层lambda接收到的args透传给这个闭包,相当于直接把闭包对象本身作为值传给了fn,最终自然会返回嵌套闭包,而不是预期的计算结果。
递归逻辑梳理
compose的执行规则和Graham原版保持一致:传入的函数列表从左到右是从最外层到最内层的嵌套顺序,最终复合函数收到的实参,会先传给最内层(列表最右侧)的函数计算,结果逐层向外传递给外层函数。
递归的两个核心分支:
- 基例:当函数列表只剩1个最内层函数时,复合函数直接把收到的所有实参apply给这个函数,返回计算结果
- 递推:当函数列表为
(当前最外层函数 . 剩余函数列表)时,复合函数收到实参后,先把实参传给剩余函数列表生成的复合函数拿到中间值,再把这个中间值传给当前最外层函数计算
正确实现代码
(defun rec-compose (&rest functions) (destructuring-bind (fn . fns) functions (lambda (&rest args) (if (null fns) (apply fn args) (funcall fn (apply (apply #'rec-compose fns) args))))))
效果验证
用你之前的测试用例验证:
;; 计算逻辑为 list(round(sqrt(11))) (funcall (rec-compose #'list #'round #'sqrt) 11) ;; 输出 (3),与原版compose行为完全一致 ;; 复刻lst-gt10p的用例 (setf (symbol-function 'lst-gt10p) (rec-compose #'list #'(lambda (x) (and (> x 10) t)))) (lst-gt10p 11) ;; 输出 (T),符合预期
内容的提问来源于stack exchange,提问作者lupl
相关产品推荐
相关产品推荐

