试图检查列表中的所有元素是否都是唯一的

时间:2015-05-31 11:13:12

标签: scheme equality member

正如标题所示,我正在尝试编写一个方案函数,用于检查列表中的所有元素是否都是唯一的。我写了一些我认为应该有用的代码:

(define are-all-unique?
      (lambda (v)
        (if (member (car v) (cdr v))
            #f
            (if (pair? v)
                (are-all-unique? (cdr v))
                #t))))

并且在错误的情况下它可以正常工作,但是如果我写的话:

 (are-all-unique? '(1 2 3))

它返回:

Exception in car: () is not a pair

有没有人知道如何解决这个问题,以及我做错了什么? :)

1 个答案:

答案 0 :(得分:4)

好吧,正如您的错误消息所述,您正在尝试将空列表传递给car。至于为什么正在发生,让我们来看看你的代码。

众所周知,我们需要将cons单元格传递给carcdr才能使其正常工作。我们使用您正在执行的pair?检查此属性。 你正在做的时候,问题是

调试这样的函数的最佳方法是跟踪将错误输入(在本例中为'())传递给函数时发生的情况。它要做的第一件事是在if语句中运行测试:(member (car v) (cdr v))。现在,由于我们正在跟踪的输入是空列表,因此每次都会失败。你想要的是更像这样的东西:

;; are-all-equal? is a poor choice of function name, by the way, since that's
;; not really what this function checks
(define are-all-unique? 
  (lambda (v)
    (if (pair? v)
        ; The only way that this branch will ever execute is
        ; if (pair? v) is true, so we know that (car v) and (cdr v)
        ; will never raise any exceptions
        (and (not (member (car v) (cdr v)))
             (are-all-unique? (cdr v)))
        #t)))

这里需要注意的是此版本函数的控制流结构:正确的列表是cons单元格或空列表,因此我们的函数中有两种情况(每种情况一种情况) )。在编写处理列表的函数时,应该(在大多数情况下)决定在非空和空的情况下你想要做什么,并且在函数内部做的第一件事就是将list参数发送到适当的case。这种方法在进行结构递归时是合适的(即,用我的一个新生教授的话来说,'数据结构通知代码的结构')。