Racket(Lisp)程序计算正常却报错:期望可应用参数的过程
帕斯卡三角Racket程序执行正确却报错的原因分析
问题描述
为何以下生成帕斯卡三角的Racket程序能正确完成计算并输出结果,却仍出现错误提示application: not a procedure; expected a procedure that can be applied to arguments?我已确保print_pascal函数在所有可返回位置都返回#f。
原代码
#!/usr/bin/racket #lang racket/base (define (pascal_value row column) (cond ((< row 0) 0) ((< column 0) 0) ((= column 1) 1) ((= column row) 1) ((> column row) 0) (else (+ (pascal_value (- row 1) (- column 1)) (pascal_value (- row 1) column ))) ) ) (pascal_value 6 4) (define (pascal_triangle max_rows) (define (print_pascal row column) (cond ((> row max_rows) (printf "done\n") #f) (else (cond ((= column row) ( (printf "~a\n" (pascal_value row column)) (print_pascal (+ row 1) 1) ) #f) (else ( (printf "~a " (pascal_value row column)) (print_pascal row (+ column 1)) ) #f ) ) #f ) ) #f ) (print_pascal 1 1) ) (pascal_triangle 7)
执行输出
[I] ➜ ./1_12.lisp 10 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 done application: not a procedure; expected a procedure that can be applied to arguments given: #<void> context...: /home/ubuntu/Software/code_samples/sicp_exercises/1_12.lisp:17:2: print_pascal [repeats 28 more times] body of "/home/ubuntu/Software/code_samples/sicp_exercises/1_12.lisp"
错误原因
问题出在多余的括号嵌套上。在Racket中,括号()的核心作用是调用过程,如果你把多个表达式用额外的括号包裹,Racket会把第一个表达式的返回值当作可调用的过程,去执行后面的参数。
比如原代码里的这段:
((printf "~a\n" (pascal_value row column)) (print_pascal (+ row 1) 1))
printf执行后返回的是#<void>,Racket会尝试把这个#<void>当作过程去调用后面的(print_pascal ...),但#<void>并非可调用的过程,因此触发了application: not a procedure错误。
程序能正常输出结果,是因为printf和递归调用print_pascal已经完成了执行,但执行结束后这个错误逻辑被触发,导致报错。你添加的#f是在嵌套括号之外,无法阻止括号内的错误逻辑执行。
修正后代码
(define (pascal_triangle max_rows) (define (print_pascal row column) (cond ((> row max_rows) (printf "done\n")) (else (cond ((= column row) (printf "~a\n" (pascal_value row column)) (print_pascal (+ row 1) 1)) (else (printf "~a " (pascal_value row column)) (print_pascal row (+ column 1))))) )) (print_pascal 1 1) ) (pascal_triangle 9)
修正时去掉了多余的嵌套括号,让多个表达式直接按顺序执行(Racket中(expr1 expr2)会先执行expr1,再执行expr2,最终返回expr2的结果)。同时无需额外返回#f,因为cond会自动返回最后一个表达式的结果,而printf返回的#<void>不会引发错误——因为没有尝试把它当作过程调用。
内容的提问来源于stack exchange,提问作者urmish
相关产品推荐
相关产品推荐

