我是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")`
答案 0 :(得分:13)
注意:这是从Recursive range in Lisp adds a period?的答案中蚕食的,这实际上是在问一个不同的问题。但是,如何打印对的说明是相同的。其余的答案是不同的。
你的问题表现出一些误解,但我认为我们可以解决它。
cons
的第一个[参数]可以是符号或列表 无所谓。但特别是第二个元素必须是符号,如果 它不是,可能是一个列表,然后我们不能创建一对 内置的cons程序。
这不正确。您可以使用您喜欢的任何参数调用cons
,并且总是返回cons
单元格,其car
与{cons
的第一个参数相同1}},其cdr
与cons
的第二个参数相同。也就是说,cons
唯一重要的是它满足方程式
(eq? a (car (cons a b))
(eq? b (cdr (cons a b))
那么可以创建一对2个列表???好吧,我在想 一个解决方案是将列表转换为符号,但实际上是那些 2完全不同的东西 - >我不明白。
很有可能;如果您有两个列表,例如list1
和list2
,则可以创建car
为list1
且其cdr
为list2
的对只需致电(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
,那么 会返回一个包含预期car
和cdr
的对,但不会打印.
符号。如,
(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")
尽管如此,您仍然可以使用car
和cdr
来解决这两个属性:
(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)
这完全有效。您仍然可以像往常一样使用car
和cdr
分别访问这两个列表:
(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
。