我正在尝试编写一个程序来检查列表列表是否具有某个属性(对问题不重要)。一路上我发现有必要生成一个给定列表的“非对角线对”列表,所以我写了一个宏,它接受一个列表并定义了两个对的列表(笛卡尔积的列表版本)我将称之为该列表的“对角线”(形式为'(x x)
的对)。我为实现这一目标而编写的代码如下:
;;;These first two definitions are 'extended' car and cdr
;;;I only did this because the (prod a b) code below threw errors otherwise
(define (xcar a) (cond ((null? a) '()) ((car a))))
(define (xcdr a) (cond ((null? a) '()) ((cdr a))))
;;;This defines a pre-product, i.e. all pairs with the first element of the first list
(define (pre-prod a b)
(cond ((or (null? a) (null? b)) '())
((append (list (list (xcar a) (xcar b))) (pre-prod a (xcdr b))))))
;;;This defines the full product of the list
(define (prod a b)
(cond ((null? a) '())
((append (pre-prod a b) (prod (xcdr a) b)))))
;;;This defines the diagonal of the list
(define (diagonal a)
(cond ((null? a) '())
((append
(list (list (car a) (car a)))
(diagonal (cdr a))))))
太棒了,那些代码似乎都像我想要的那样工作。我接下来需要采用set-minus的列表版本。我在an answer here中找到了以下代码:
;;;Returns #t if x is an element of lst and #f otherwise
(define (element? x lst)
(cond ((null? lst) #f)
((eq? x (car lst)) #t)
(#t (element? x (cdr lst)))))
;;;Takes list a and removes all elements of list b from it
(define (list-minus a b)
(cond ((null? a) '())
((element? (car a) b)
(list-minus (cdr a) b))
(#t (cons (car a) (list-minus (cdr a) b)))))
很酷,这似乎对它需要做的事情很好。现在我所要做的就是让DrRacket返回正确的对列表(删除对角线)。我认为以下代码应该这样做:
(define (proper-pairs a) (list-minus (prod a a) (diagonal a)))
现在我在一些简单的东西上测试这个新函数,它应该返回'()
:
> (proper-pairs '(1))
=> '((1 1))
什么?我已经尝试了很多例子,多次重写代码,在各种列表列表上尝试过。我总是提出以下问题:list-minus
不会从列表列表中删除列表。
问题1:为什么list-minus
会在列表列表中出现这种异常行为,同时在以下示例中完全按预期工作:
> (list-minus '(1 2 3 4 5) '(x 2 4 m))
=> '(1 3 5)
问题2:如何修复list-minus
代码,还是必须从头开始?
问题3:在上面第一行代码中,我必须“扩展”car
和cdr
,以确保prod
函数能够不要抛出错误。我做了什么标准技巧?我不确定我理解它为什么会有所作为(我只是尝试过它,因为我预感它可能会起作用)。
免责声明:我不是程序员。我正在尝试学习函数式编程作为测试各种(数学)猜想和编译一些示例的方法。我完全没有编写代码的经验,除了我在DrRacket和旧的TI-83计算器上完成的一些非常愚蠢的小部分。话虽如此,可能有必要为我“愚弄”你的答案。
抱歉长篇大论,谢谢你的时间!
答案 0 :(得分:3)
问题在于,与其他语言一样,Racket中的相等性由不同的运算符表示,必须根据以下内容进行选择:
必须比较的数据类型
比较的语义。
一般提示是你应该使用逻辑上更简单的操作符,并且可以用于某个比较。
例如,您应该=
使用compare numbers; eq?
到compare objects for identity,即如果内存中的相同对象,则两个值相等; eqv?
如果你想检查两个值are the same object in memory or are equal numbers or equal characters; equal?
如果您想要检查两个值是eqv?
还是它们是相等的字符串,或者它们是结构化数据(如列表)是否结构等效(请参阅{{ 3}}),即递归等价。
例如:
(equal? '(a (b)) '(a (b))) ; => true, two different objects with the same structure
(eqv? '(a (b)) '(a (b))) ; => false, two different objects
(eq? '(a (b)) '(a (b))) ; => false, as for eqv?
(let ((x '(a (b))))
(eq? x x)) ; true, they are the same object