正如标题所示,我正在尝试编写一个方案函数,用于检查列表中的所有元素是否都是唯一的。我写了一些我认为应该有用的代码:
(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
有没有人知道如何解决这个问题,以及我做错了什么? :)
答案 0 :(得分:4)
好吧,正如您的错误消息所述,您正在尝试将空列表传递给car
。至于为什么正在发生,让我们来看看你的代码。
众所周知,我们需要将cons
单元格传递给car
和cdr
才能使其正常工作。我们使用您正在执行的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。这种方法在进行结构递归时是合适的(即,用我的一个新生教授的话来说,'数据结构通知代码的结构')。