Racket - 构建内置成员函数

Racket - Building the built-in member function

我喜欢编写与内置函数相同的代码。这对我来说总是很好的锻炼。

racket 中有一个名为 "member" 的内置函数,它检查某个元素是否在列表中。如果为真,则函数 returns rest/cdr o 列表 如果为假,则函数 returns #f。示例:

> (member 2 (list 1 2 3 4))
'(2 3 4)

> (member 9 (list 1 2 3 4))
#f

我做了以下代码:

(require racket/trace)

(define (member-mine lista num)
  (cond ((equal? (car lista) num) (cdr lista))
        ((equal? (car lista) '()) #f)
        (else (member-mine (cdr lista) num))))

(define small-list (list 1 2 3 4 5 6 7 8))

(trace member-mine)

而且,当我尝试将它与酷工具跟踪一起使用时,我部分成功了。

通话中:

(member-mine small-list 1)

Returns:

>(member-mine '(1 2 3 4 5 6 7 8) 1)
<'(2 3 4 5 6 7 8)

通话中:

(member-mine small-list 8)

Returns:

>(member-mine '(1 2 3 4 5 6 7 8) 8)
>(member-mine '(2 3 4 5 6 7 8) 8)
>(member-mine '(3 4 5 6 7 8) 8)
>(member-mine '(4 5 6 7 8) 8)
>(member-mine '(5 6 7 8) 8)
>(member-mine '(6 7 8) 8)
>(member-mine '(7 8) 8)
>(member-mine '(8) 8)
<'()

问题是当我调用一个不在给定列表中的元素时。输出应该是#f:

(member-mine small-list 9)

其中returns是一个错误:

>(member-mine '(1 2 3 4 5 6 7 8) 9)
>(member-mine '(2 3 4 5 6 7 8) 9)
>(member-mine '(3 4 5 6 7 8) 9)
>(member-mine '(4 5 6 7 8) 9)
>(member-mine '(5 6 7 8) 9)
>(member-mine '(6 7 8) 9)
>(member-mine '(7 8) 9)
>(member-mine '(8) 9)
>(member-mine '() 9)
. . car: contract violation
  expected: pair?
  given: '()

如何处理空的?

将空格移动到条件的第一个分支。当空列表在最后的递归调用中传递给您的函数时,您请求列表的 car,这无法完成,因为列表是空的。将空 case 放在拳头上应该会导致函数在到达对 car.

的调用之前以 #f 终止

您的代码存在一些问题。作为第一个观察结果,您已经切换了合同,以便列表排在第一位而不是最后一位。

您似乎也在检查其中一个元素是否为空列表而不是列表本身。因此,在这种情况下,您的 member 将以 #f 终止:

(member-mine '(() 1 2 3 4 5 6 7 8) 1) ; ==> #f

因此您的成员应该检查整个参数是否为 null?empty?)或者检查它是否不是 pair?。然后它应该评估为 #f.

如果第一个元素与您的搜索相匹配,那么原始 member 计算整个参数并将匹配作为第一个元素,而不是像您的代码中那样 cdr

另一种检查空列表的方法是检查它的长度:

(define (member-mine lista num)
  (cond
    ((equal? (length lista) 0) #f)    ; '=' can also be used instead of 'equal?'
    ((equal? (car lista) num) (cdr lista))
    (else (member-mine (cdr lista) num))))

(define small-list (list 1 2 3 4 5 6 7 8))

(member-mine small-list 9)

输出:

#f

但正确的做法是:

(empty? lista)  or (null? lista)