方案中的点符号

时间:2013-11-26 12:10:05

标签: scheme

我是Scheme编程的初学者。我知道Scheme中的点符号用于表示一对符号,例如'(a . b)

第一个元素可以是符号,也可以是列表,无关紧要。但特别是第二个元素必须是符号,如果不是,可能是一个列表,那么我们就不能创建一个内置cons过程的对。

那么可以创建一对2个列表???嗯,我想的解决方案是将列表转换为符号,但实际上这些是完全不同的2 - >我不明白。

这是我写的代码:

(define compare-attrs
  (lambda (attribute1 attribute2)
    (if (or (and (null? attribute1) (null? attribute2)) (and (not (null? attribute1)) (not (null? attribute2))))
        (cons attribute1 attribute2)
        #f)))

其中attribute1和attribute2是2个列表,我的输出是:

attribute1 atrribute2

预期输出:'(attribute1。attribute2)

请解释一下。提前谢谢!!!

编辑:添加比较attrs功能

函数compare-attrs用于提取描述实体属性的部分,并cons将它们组成一对,实体定义如下:

(entity e0 (prov:label "entity e0")
(entity e1 (prov:location "London")

因此,这些实体的属性为(prov:label "entity e0")(prov:location "London")。 应用函数compare-attrs时,因为这些属性不是null,所以我期望的输出是

`(prov:label "entity e0") . (prov:location "London")`

3 个答案:

答案 0 :(得分:13)

注意:这是从Recursive range in Lisp adds a period?的答案中蚕食的,这实际上是在问一个不同的问题。但是,如何打印对的说明是相同的。其余的答案是不同的。

你的问题表现出一些误解,但我认为我们可以解决它。

  

cons的第一个[参数]可以是符号或列表   无所谓。但特别是第二个元素必须是符号,如果   它不是,可能是一个列表,然后我们不能创建一对   内置的cons程序。

这不正确。您可以使用您喜欢的任何参数调用cons,并且总是返回cons单元格,其car与{cons的第一个参数相同1}},其cdrcons的第二个参数相同。也就是说,cons唯一重要的是它满足方程式

(eq? a (car (cons a b))
(eq? b (cdr (cons a b))
  

那么可以创建一对2个列表???好吧,我在想   一个解决方案是将列表转换为符号,但实际上是那些   2完全不同的东西 - >我不明白。

很有可能;如果您有两个列表,例如list1list2,则可以创建carlist1且其cdrlist2的对只需致电(cons list1 list2)即可。现在,我认为你遇到的问题是你希望 (<value-of-list1> . <value-of-list2>)作为输出,你会看到一些不同的东西。为了解释这是为什么,我们需要了解如何在Lisps中表示列表,以及如何打印对。

Scheme中的列表是空列表()(在某些Lisp中也称为nil),或者是car(也称为first的缺点列表)是列表的一个元素,其cdr(也称为rest)是列表的其余部分(即另一个列表),或者是终止列表的原子。传统的终结符是空列表();被()终止的列表被称为“正确列表”。被任何其他原子终止的列表称为“不正确的列表”。列表(1 2 3 4 5)包含元素1,2,3,4和5,并由()终止。您可以通过

构建它
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 ())))))

现在,当系统打印一个缺点单元时,一般情况是通过

打印它
(car . cdr)

例如,(cons 1 2)的结果打印为

(1 . 2)

由于列表是由增量单元格构建的,因此您也可以将此表示法用于列表:

'(1 2 3 4 5) ==
'(1 . (2 . (3 . (4 . (5 . ())))))
但是,这是相当笨重的,所以大多数lisps(我所知道的)都有一个打印cons单元格的特殊情况:如果cdr是一个列表(另一个cons单元格,或() ),然后不打印.,并且不打印cdr的周围括号(否则它将具有,因为它是一个列表)。

现在我们可以解释为什么(cons list1 list2)的结果看起来不像(<value-of-list1> . <value-of-list2>)。如果您使用两个列表致电cons,那么 会返回一个包含预期carcdr的对,但不会打印.符号。如,

(cons '(1 2 3) '(a b c))
;=> ((1 2 3) . (a b c))   ; which is typically *printed* as
;=> ((1 2 3) a b c)

但同样,印刷表示并不重要,只要以下等式成立:

(eq? a (car (cons a b))
(eq? b (cdr (cons a b))

果然:

(car (cons '(1 2 3) '(a b c)))
;=> (1 2 3)

(cdr (cons '(1 2 3) '(a b c)))
;=> (a b c)

在你问的具体例子中,考虑一下你致电

时会发生什么
(cons '(prov:label "entity e0") '(prov:location "London"))

事实上,结果是

((prov:label "entity e0") . (prov:location "London"))

但是,由于打印规则,打印

((prov:label "entity e0") prov:location "London")

尽管如此,您仍然可以使用carcdr来解决这两个属性:

(car '((prov:label "entity e0") prov:location "London"))
;=> (prov:label "entity e0")

(cdr '((prov:label "entity e0") prov:location "London"))
;=> (prov:location "London")

这就是你以后真正需要做的所有事情。

答案 1 :(得分:5)

Scheme中的点符号或任何其他LISP方言用于创建任意两个值的点对。值可以是符号,列表或其他任何值。它的价值并不重要。例如:

'(author . aaditmshah) => (author . aaditmshah)
'((a b c) . (d e f))   => ((a b c) d e f)

如您所见,如果您创建两个列表的点对,则第一个列表将添加到第二个列表的头部。这是因为LISP中的列表是嵌套的点对:

'(a . (b . (c . ())))  => '(a b c)

因此,当您撰写'((a b c) . (d e f))时,就好像您正在编写以下内容一样:

'((a b c) . (d . (e . (f . ())))) => '((a b c) d e f)

这完全有效。您仍然可以像往常一样使用carcdr分别访问这两个列表:

(car '((a b c) . (d e f))) => (a b c)
(cdr '((a b c) . (d e f))) => (d e f)

我不确定你的compare-attrs函数应该做什么。您的if分支返回cons单元格,而您的else分支返回布尔值。对我来说,这绝对没有意义。函数的返回类型应该是常量。

也许你没有正确地提出你的问题,因为我不确定你的问题是什么。如果你还有任何疑问,请告诉我。

答案 2 :(得分:1)

我对方案中数据结构的回忆是,你宁愿避免使用一对虚线原子(即(a . b)),因为它代表了将两个原子结合在一起的结果。如果您查看第3页的The Little Schemer,您会看到:


缺点法则

原始缺点有两个参数。 缺点的第二个参数必须是一个列表。 结果是一个列表。


如果你已经阅读了其他答案,你知道这不是真的。老实说,由SICP禁止的与Scheme数据结构有关的事情是根据列表定义数据结构布局,然后使用很少的函数作为访问器。

所以让我们说你想要一个元组 - 你可以让它看起来像(a b)这是完全合理的。然后你可以编写这些函数:

(define (make-tuple a b) (list a b))

(define (tuple-first tup) (car tup))
(define (tuple-second tup) (car (cdr tup)))
(define (tuple? tup) (and (list? tup) (eq? 2 (length tup))))

现在它给了我访问器函数和构造函数,我是黄金。但这并不是说这是实现这一目标的唯一方法。你可以直接前进并使用对:

(define (make-tuple a b) (cons a b))

(define (tuple-first tup) (car tup))
(define (tuple-second tup) (cdr tup))
(define (tuple? tup) (pair? tup))

因此,在您的代码中,您可以使用此处的构造函数来创建所需的元组。

一般来说,你的compare-attrs函数很奇怪,因为这个名字并没有让我们真正了解你想要做什么。我更倾向于这样写:

(define (compare-attrs a1 a2)
    (or
        (and (null? a1) (null? a2))
        (and (not (null? a1)) (not (null? a2)))
    ))

(define (join-populated-attrs a1 a2)
    (if (compare-attrs a1 a2) (make-tuple a1 a2) '()))

仍然觉得很有趣,因为你接受了两个null属性,但这可能是你所有问题域的一部分。

我还应该说,如果您希望输出以特定方式显示,您可能也应该编写print-tuple