MIT-Scheme中square等对象无法应用的报错问题排查
问题:Scheme中
func_polynomial_minimal_unit调用报错分析 背景
我正在自学MIT 6.5151课程,已完成CS 61AS Unit 0预习,按要求阅读了SICP 1至2.1章节、CS 61A讲义2.2.1章节,以及《Software Design for Flexibility (SDF)》的序言、第1章和Scheme相关附录。当前使用MIT-Scheme,正在学习SDF第2章并完成习题2.5(b)。
问题描述
我编写的func_polynomial_minimal_unit过程,预期实现类似(f(f(g(x))))的嵌套调用(例如调用(func_polynomial_minimal_unit '((f . 2) (g . 1)))),但运行时出现以下报错:
;;The object square is not applicable.;;The object (lambda (x) (square x)) is not applicable.
单独测试相关过程时均可正常调用,但调用func_polynomial_minimal_unit时触发错误。
代码示例
(define (compose f g) (define (the-composition . args) (call-with-values (lambda () (apply g args)) f)) the-composition) (define (iterate n) (define (the-iterator f) (if (= n 0) identity (compose f ((iterate (- n 1)) f)))) the-iterator) (define (identity x) x) (define (func_polynomial_minimal_unit . func_pow_pair_lst) (if (null? (car func_pow_pair_lst)) ; contain one null pair identity (let ((cur_func_pow (caar func_pow_pair_lst))) (newline) (display cur_func_pow) (compose ((iterate (cdr cur_func_pow)) (car cur_func_pow)) (func_polynomial_minimal_unit (cdr func_pow_pair_lst)))))) ;; equivalent lambda for the following `func_polynomial_minimal_unit`. ((lambda (x) (expt (* x 9) (expt 2 3))) 3) ;; these works ((compose ((iterate 3) (lambda (x) (square x))) (lambda (x) (* 3 x))) 3) ((compose ((iterate 3) square) (lambda (x) (* 3 x))) 3) ;; these doesn't work ((func_polynomial_minimal_unit '((square . 3) ((lambda (x) (* 3 x)) . 2))) 3) ((func_polynomial_minimal_unit '(((lambda (x) (square x)) . 3) ((lambda (x) (* 3 x)) . 2))) 3)
原因分析
报错的核心问题是:你传递给func_polynomial_minimal_unit的参数是符号和lambda表达式的字面量数据,而非实际可调用的过程对象:
- 当你写
'((square . 3) ...)时,square只是一个符号(symbol),不是指向square过程的引用;同理'(lambda (x) (square x))只是一个列表形式的字面量,不是可执行的lambda过程。 - 单独测试时,你直接传递的是
square过程或(lambda (x) ...)这样的可执行对象,所以能正常工作。
解决方案
有两种常见方式可以修复这个问题:
方式1:直接传递过程对象(推荐)
修改调用方式,去掉引号,把过程作为参数直接传入;同时调整func_polynomial_minimal_unit的参数处理逻辑:
(define (func_polynomial_minimal_unit . func_pow_pair_lst) (if (null? func_pow_pair_lst) ; 检查是否没有剩余参数 identity (let ((cur_func_pow (car func_pow_pair_lst))) (compose ((iterate (cdr cur_func_pow)) (car cur_func_pow)) (apply func_polynomial_minimal_unit (cdr func_pow_pair_lst)))))) ;; 调用示例 ((func_polynomial_minimal_unit (cons square 3) (cons (lambda (x) (* 3 x)) 2)) 3)
方式2:在过程内部解析字面量为过程
如果坚持要传递带引号的列表,需要在func_polynomial_minimal_unit里把符号或lambda字面量转换为可调用过程:
(define (resolve-proc proc-expr) (eval proc-expr (interaction-environment))) (define (func_polynomial_minimal_unit func_pow_pair_lst) ; 改为接收单个列表参数 (if (null? func_pow_pair_lst) identity (let* ((cur_func_pow (car func_pow_pair_lst)) (proc (resolve-proc (car cur_func_pow))) (pow (cdr cur_func_pow))) (compose ((iterate pow) proc) (func_polynomial_minimal_unit (cdr func_pow_pair_lst)))))) ;; 调用示例(保持原格式) ((func_polynomial_minimal_unit '((square . 3) ((lambda (x) (* 3 x)) . 2))) 3)
注意:使用eval会引入环境相关的潜在问题,在复杂场景下需要谨慎处理。
内容的提问来源于stack exchange,提问作者An5Drama
相关产品推荐
相关产品推荐

