SICP练习1.3:Racket用when实现的函数为何返回#<void>
问题根因
代码返回#<void>是两个Racket基础语义理解偏差导致的:
- Racket过程的返回值固定为过程体内最后一个求值完成的表达式的结果,中间表达式算出的值如果没有被绑定、也没有成为最后一个返回表达式,会被直接丢弃。
when是面向副作用操作(打印、变量赋值等)设计的语法,不会在条件命中时中断后续代码执行:条件成立时它会执行内部语句并返回内部最后一个语句的值,条件不成立时直接返回#<void>,没有任何分支跳转、提前返回的效果。
拿你测试用的(procsq 1 2 3)举例,执行流是:
- 第一个
when条件成立,算出两个大数的平方和13,但值直接被丢弃,继续执行后续代码 - 第二个
when条件也成立,重复计算一次13,同样丢弃,继续向下 - 剩下四个
when的判断条件全部不成立,每个都返回#<void> - 整个过程最后执行的是第六个
when,返回#<void>,自然最终输出就是void
而(procsq 3 2 1)能返回正确结果纯属于巧合——这个入参刚好命中第六个when,最后一个表达式的计算结果是正确的平方和,才碰巧返回了预期值。
修正方法
需要根据条件返回值的场景不要用when,替换为专门做值分支的cond即可。另外你原来的6个条件判断有大量重复,其实逻辑可以简化:只要找到三个数里最小的那个,剩下两个数算平方和就行,不需要枚举所有排列:
#!/usr/bin/env racket #lang racket/base (define (square x) (* x x)) (define (procsq a b c) (cond [(and (<= a b) (<= a c)) (+ (square b) (square c))] [(and (<= b a) (<= b c)) (+ (square a) (square c))] [else (+ (square a) (square b))])) (displayln (procsq 1 2 3)) ; 输出13 (displayln (procsq 3 2 1)) ; 输出13 (displayln (procsq 3 1 2)) ; 输出13
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

