1

我正在使用的平台是 DrScheme。

我已经看到一对(a b)[constructed by (cons a b)] 在语言中实现,就像一个看起来像这样的过程:

(define (cons a b)
  (lambda(pick)
    (cond ((= pick 1) a)
          ((= pick 2) b))))

和选择器:

(define (car x) (x 1))
(define (cdr x) (x 2))

然后是列表,使用表达式 like 构造(cons a (cons b (cons c (cons ...))))

现在,我试图理解的是这个(在 DrScheme 的提示下输入):

> (define l1 '(a b c))
> (define l2 (list 'a 'b 'c))
> l1
(a b c)
> l2
(a b c)
> (eq? l1 l2)
#f

好的,l2 只是一个列表(即程序等),就像我描述的 abode 一样,但是…… l1 是什么一个符号?字符序列?不管它是什么,它是如何在语言中实现的?谢谢!

4

3 回答 3

3

l1也只是一个包含相同元素的列表。请注意,这也返回#f

(define l1 '(a b c))
(define l2 '(a b c))
(eq? l1 l2)

虽然这会返回#t

(define l1 '(a b c))
(define l2 (list 'a 'b 'c))
(equal? l1 l2)

原因是eq?检查l1l2是否引用内存中的同一个对象,同时equal?检查它们是否具有相同的内容。

于 2010-06-27T21:27:09.140 回答
1

列表不是atom,这是这里的重要部分。符号虽然是原子,但这意味着当它们相同时,它们驻留在同一内存中,它们就像数字一样,确实可以看作是指针。符号也不是可变的,符号foo就像一个数字3

然而,列表不是原子,两个列表或字符串具有相同内容的向量可以很好地驻留在内存的两个不同位置。

eq?仅对内存位置进行测试。eqv?等效测试,那是模糊的,它取决于哪个实现,Scheme标准对此相当自由,它只说它必须至少是eq?基本的超集。equal?另一方面,对结构相等性进行测试并递归执行,因此这是一个非常昂贵的操作,这就是为什么符号通常比字符串更适合标识符。

(define l1 (list 1 2 3))
(define l2 (list 1 2 3))
(eq? l1 l2) ; ===> #f in most implementations
(equal? l1 l2) ; ===> #t in all implementations
(eqv? l1 l2) ; ===> #t in some implementations
(define l3 (cdr l1))
(define l4 (cdr l1))
(eq? l3 l4) ; ===> #t, this means that they 'share memory', if you change l3 or l4, l1 will change with it, beware. This is how car and cdr work, they do not copy.
(define l6 (cons 1 l4));
(eq? l1 l6) ; ===> #f again, cons does allocate new memory, but the tails may very well share it, s in this case, l6 does share its tail with all lists except l2 here in memory. 

另外,有点术语, cons 创建一个对,这与两个元素的列表不同,它创建一个对(a . b),该列表(a b)实际上与该对相同(a . (b . ()))

此外, cons 和 car 和 cdr 是原语,您在下面看到的实现是计算机程序的结构和实现中的演示,表明它们并不是严格需要的,但是将它们作为原语会显着提高性能,所以最好不要重新定义你的缺点、汽车和 cdrs。

于 2010-06-27T23:11:39.657 回答
1
> > (define l1 '(a b c))
> > (define l2 (list 'a 'b 'c))
> > l1 (a b c)
> > l2 (a b c)
> > (eq? l1 l2)
> #f

好的,l2 只是一个列表(即程序等),就像我描述的 abode 一样,但是……l1 是什么?一个符号?字符序列?不管它是什么,它是如何在语言中实现的?谢谢!

定义具有以下形式:

(定义 <名称> <表达式>)

在运行时,表达式 <expression> 被计算,结果是一个值。该值存储在内存中的某个位置。为了在其他计算中使用此值,可以使用名称 <name>。术语是 <name> 绑定到该值。

需要注意的重要一点是,名称 <name> 仅出现在您的源代码中。它在运行时不存在。因此,询问名称 l1 是否是一个符号是没有意义的。

编译器翻译(定义 <name> <expression>)的一种可能策略如下(忽略 Scheme 实现具有垃圾收集)。

  1. 为指针 p 保留一个存储单元 m
  2. 计算值 v 的输出代码
  3. 将包含 v 的存储单元的地址存储在存储单元 m 中。

请注意,名称 <name> 不会出现在此列表中。

于 2010-06-30T13:47:12.613 回答