DrRacket/Scheme求二次方程根程序报错:not a procedure
问题分析与修正
你遇到的错误核心是多余的括号导致的过程调用错误,咱们一步步拆解:
错误根源
看你写的roots函数:
(define roots (lambda (a b c) ((if (> (D a b c) 0) (cons (/ (+ (- b) (sqrt (D a b c))) (* 2 a)) (/ (- (- b) (sqrt (D a b c))) (* 2 a))) #f)))
注意最外层的((if ...))——在Scheme里,任何被括号包裹的表达式都会被当作过程调用处理。这里if表达式的结果是(cons ... ...)生成的点对(比如(-1 . -2)),但外层的括号试图把这个点对当作可调用的过程来执行,而点对并不是过程,所以就报了application: not a procedure的错误。
修正后的代码
只需要把外层多余的括号去掉,让if直接返回对应的结果即可:
(define na2 (lambda (x) (* x x))) (define D (lambda (a b c) (- (na2 b) (* 4 a c)))) (define roots (lambda (a b c) (if (> (D a b c) 0) (cons (/ (+ (- b) (sqrt (D a b c))) (* 2 a)) (/ (- (- b) (sqrt (D a b c))) (* 2 a))) #f)))
现在执行(roots 1 3 2)就会正确返回(-1 . -2),不会报错了。
额外优化建议
你的代码里重复计算了三次(D a b c)和两次sqrt,可以把判别式的结果先存起来,既提高效率又让代码更清晰:
(define na2 (lambda (x) (* x x))) (define D (lambda (a b c) (- (na2 b) (* 4 a c)))) (define roots (lambda (a b c) (let ((discriminant (D a b c))) (if (> discriminant 0) (let ((sqrt-d (sqrt discriminant))) (cons (/ (+ (- b) sqrt-d) (* 2 a)) (/ (- (- b) sqrt-d) (* 2 a)))) #f))))
这样只计算一次判别式和一次平方根,代码可读性也更好。
内容的提问来源于stack exchange,提问作者SheldonCopper
相关产品推荐
相关产品推荐

