自定义城市ADT中get-lon返回列表而非数值的问题排查
城市ADT中get-lon返回列表而非数值的问题排查
问题重现
我们定义了城市抽象数据类型(ADT),包含构造器make-city和选择器get-name、get-lat、get-lon,代码实现如下:
(define (make-city name lat lon) (cons name (cons lat (cons lon null)))) (define (get-name make-city) (car make-city)) (define (get-lat make-city) (car (cdr make-city))) (define (get-lon make-city) (cdr (cdr make-city))) (define berkeley (make-city 'Berkeley 122 37)) (get-name berkeley) 'Berkeley (get-lat berkeley) 122 (get-lon berkeley) '(37)
调用(get-lon berkeley)返回'(37),但预期输出为37,需要排查代码错误。
错误原因
问题出在构造器的结构设计和选择器的匹配逻辑不统一:
- 构造器
make-city中,(cons lon null)等价于(list lon),把经度值包装成了一个单元素列表,最终生成的城市结构是(Berkeley . (122 . (37 . ()))),此时(cdr (cdr berkeley))取到的是(37 . ()),也就是显示为'(37)的列表。 - 选择器
get-lon直接取(cdr (cdr make-city)),拿到的是这个单元素列表,而非列表里的数值37。
修正方案
有两种可行的修正方式,推荐第一种(更符合Scheme配对结构的简洁设计):
方案一:修正构造器,让经度作为原子值存储
调整make-city的实现,去掉最后一层cons和null,让经度直接作为配对结构的最后一个元素:
(define (make-city name lat lon) (cons name (cons lat lon))) ; 直接将lon作为最终的cdr部分 (define (get-name city) (car city)) (define (get-lat city) (car (cdr city))) (define (get-lon city) (cdr (cdr city))) ; 此时直接取到的就是lon的数值 (define berkeley (make-city 'Berkeley 122 37)) (get-name berkeley) ; 输出 'Berkeley (get-lat berkeley) ; 输出 122 (get-lon berkeley) ; 输出 37
方案二:保留原构造器,修正选择器逻辑
如果需要保留原构造器的结构,修改get-lon,从单元素列表中取出数值:
(define (make-city name lat lon) (cons name (cons lat (cons lon null)))) (define (get-name city) (car city)) (define (get-lat city) (car (cdr city))) (define (get-lon city) (car (cdr (cdr city)))) ; 取列表的第一个元素(即数值37) (define berkeley (make-city 'Berkeley 122 37)) (get-lon berkeley) ; 输出 37
内容的提问来源于stack exchange,提问作者Proteus Yi
相关产品推荐
相关产品推荐

