假设我们有一个城市的抽象数据类型。城市有名称、纬度坐标和经度坐标

问题描述 投票:0回答:3

我们的数据抽象有一个构造函数:

(make-city name lat lon)

创建具有给定名称、纬度和经度的城市对象。 我们还有以下选择器来获取每个城市的信息:

(get-name city)   ;; Returns the city's name
(get-lat city)    ;; Returns the city's latitude
(get-lon city)    ;; Returns the city's longitude

我的代码:

(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
,我的代码有什么问题吗?

scheme racket abstraction
3个回答
3
投票

根据您的定义,

(make-city 'Berkeley 122 37)
产生以下结构:

每个节点都是一对,在这个结构中:

  • car
    选择左侧箭头指向的东西(沿着绘制的方向向下);
  • cdr
    选择右手箭头指向的东西。

所以

(cdr (cdr (make-city 'Berkeley 122 37)))
遵循两个向右的箭头来返回这个对象:

打印为

(37)

我认为通过查看这些图表应该可以清楚地了解如何解决这个问题。至少有两种方法:一种比另一种更好。

(补充一点:为什么这样的表示一般不好?)


1
投票

如果您使用 Racket,则应该使用 结构 而不是列表来表示城市。

struct
创建的默认函数名称与您的不匹配,因此您可以创建别名(或直接使用结构体生成的别名):

(struct city (name lat lon)
  #:transparent
  #:extra-constructor-name make-city)
(define get-name city-name)
(define get-lat city-lat)
(define get-lon city-lon)

与列表相比,这为您提供了更高效的存储空间和访问时间,让您可以轻松测试某个值是否是城市,并且

city?
返回列表的唯一方法是如果您使用列表而不是经度的数字(也有方法可以防止这种错误,例如
get-lon
子句或
struct 合同
如果您的基于列表的布局是作业的要求并且无法更改,那么您可以考虑使用列表访问功能,例如

#:guard

。比计算正确的 
first
car
链更容易记住。
    


0
投票
cdr

他们,这样

cons
就可以
(make-object a b)
。那么
(cons a b)
将是
object-a
并且
car
将是
object-b
。这是最有效率的。
您的解决方案使用正确的列表,并且两个值对象的正确列表版本是 

cdr

(list a b)
,这使得第一个访问器相同,但最后一个访问器将是
(cons a (cons b '()))
而不是
cadr
并且总是有一个从未使用过的空列表。
您可以通过像我的第一个示例一样提高对象的效率来解决此问题,或者保留您的解决方案并使用正确的访问器。您的选择!

© www.soinside.com 2019 - 2024. All rights reserved.