检查第一个原子与列表中的其他原子

时间:2014-11-21 15:07:10

标签: scheme

我试图检查列表中的第一个原子与列表中的其他原子,所以如果第一个原子是3而第三个原子是3,我想将它评估为假。

我有类似

的东西

(define (doubles a_list) (cond ((null? a_list) #t) (not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))

我有一种感觉,这只会检查彼此相邻的原子而不是其他原子的原子。我该怎么做才能检查第一个项目?

2 个答案:

答案 0 :(得分:2)

您希望反复比较列表的前两个元素,减少cdr

(define (unique-first? x)
   ; uncomment the following line to trace the execution
   ;(display x) (newline)
   (or (null? x) (null? (cdr x))
       (and (not (eq? (car x) (cadr x)))
            (unique-first? (cons (car x) (cddr x))))))

特殊情况说明:

  • (unique-first? '()) - > #t
  • (unique-first? '(a)) - > #t

(确实,确认"第一个元素不会出现两次"标准)。

答案 1 :(得分:1)

我有茶,我的代码审查帽和几分钟。你知道现在几点了。


你想要的是一个谓词,它会告诉你列表中第一个原子是否有重复。

(define (doubles a_list) 
  (cond ((null? a_list) #t)
        (not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))

无论如何,这都行不通,因为它有不平衡的括号。

(define (doubles a_list) 
  (cond ((null? a_list) #t)
        (not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))))

该修订版本无效,因为case中的第二个条款格式错误。奇怪的是,它似乎评价很好,但是当你调用它时,你会得到一个奇怪的错误信息

Welcome to Racket v5.3.6.
> (define (doubles a_list) 
  (cond ((null? a_list) #t)
        (not ((eq? (car a_list) (car (cdr a_list)))) (doubles(cdr a_list)))))
> (doubles (list 1 2 3 4 5 6 7 3))
application: not a procedure;
 expected a procedure that can be applied to arguments
  given: #f
  arguments...: [none]
> 

直接原因是这一点

... ((eq? (car a_list) (car (cdr a_list)))) ...

由于这个表达式周围有额外的parens,它实际意味着什么

  

“查看a_list的第一个元素是否与第二个元素相同,然后将该检查的结果称为函数”。

这不是你想要的。正确的解决方案是将not放入这些parens中,这将使其成为有效的cond子句。

(define (doubles a_list) 
  (cond ((null? a_list) #t)
        ((not (eq? (car a_list) (car (cdr a_list))))
         (doubles (cdr a_list)))))

您无法在Scheme中的空列表中调用car。对于Common Lisp中的“fine”的某些定义,这样可以正常工作,但会在这里引发错误。

> (define (doubles a_list) 
  (cond ((null? a_list) #t)
        ((not (eq? (car a_list) (car (cdr a_list))))
         (doubles (cdr a_list)))))
> (doubles (list 1 2 3 4 5 6 7 3))
car: contract violation
  expected: pair?
  given: '()
> 

此错误的原因是您要检查a_listnull?,还是稍后再调用(car (cdr a_list))。在a_list类似于(3)的情况下,您会收到此错误。对此的修复是检查a_list 或其cdr null?

(define (doubles a_list) 
  (cond ((or (null? a_list) (null? (cdr a_list))) #t)
        ((not (eq? (car a_list) (car (cdr a_list))))
         (doubles (cdr a_list)))))

> (doubles (list 1 2 3 4 5 6 7 3))
#t

现在我们已经有了一个不会出错的函数版本,让我们来看看你的逻辑。在列表中查找双精度的过程是

  • 对于长度为零或一的列表,答案为False,因为列表中没有比两个元素短的双打
  • 否则,检查列表的第一个元素是否在其余部分。
  • 如果是,答案是真的,因为我们找到了重复的

现在,您已将您的函数命名为doubles,但您的散文解释告诉我它确实应该是unique-first?。因为您不是在寻找双打,所以您需要检查列表中的第一个元素是否在同行中是唯一的。你真正想做的是

  • 对于长度为1的列表,答案是True,因为该单个元素必须是唯一的(我将假设你想要长度为零的列表相同,但根据应用程序,这可能实际上没有意义)
  • 否则,检查列表的第一个元素是否在其余部分。

转换为

(define (unique-first? a_list) 
   (if (or (null? a_list) (null? (cdr a_list)))
       #t
       (not (member? (car a_list) (cdr a_list)))))

member?函数非常简单,并且基于相同的原则。

(define (member? elem lst)
  (cond ((null? lst) #f)
        ((eq? elem (car lst)) #t)
        (else (member? elem (cdr lst)))))

最后,有几个风格点。 Scheme约定是使用尾随?来命名谓词,它会向你的函数调用者提示它将返回#t#f(我已经在上面做过),并且使用spinal-case而不是snake_case作为名称。

(define (unique-first? a-list) 
  (if (or (null? a-list) (null? (cdr a-list)))
       #t
       (not (member? (car a-list) (cdr a-list)))))