user4206400
user4206400

Reputation:

Racket - Building the built-in member function

I like writing code to the same thing that built-in functions do. It is always a great exercise for me.

In racket there is a bult-in function called "member" which checks if a certain element is inside a list. If true, the function returns the rest/cdr o the list If false, the function returns #f. Examples:

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

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

I did the following code:

(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)

And, when I try using it with the cool tool trace, I am partially successful.

Calling:

(member-mine small-list 1)

Returns:

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

Calling:

(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)
<'()

The problem is when I call an element which is not in the list given. The output should be #f:

(member-mine small-list 9)

Which returns is an error:

>(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: '()

How do I manage to deal with the empty?

Upvotes: 1

Views: 836

Answers (3)

rnso
rnso

Reputation: 24535

Another way to check empty list is to check its length:

(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)

Output:

#f

But proper way is:

(empty? lista)  or (null? lista)

Upvotes: 0

Sylwester
Sylwester

Reputation: 48745

There are some issues with your code. As a first observation you have switched the contract so that the list comes first instead of last.

It also seem that you are checking if one of the elements is the empty list and not the list itself. Thus your member would terminate with #f in this case:

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

So your member should check if the whole argument is null? (empty?) or perhaps check if it's not pair?. Then it should evaluate to #f.

If the first element matches your search, then the original member evaluates to the whole argument with the match as the first element and not the cdr like in your code.

Upvotes: 3

VergeA
VergeA

Reputation: 89

Move the empty case to be the first branch of the conditional. When the empty list is passed into your function on the final recursive call, you request the car of the list, which cannot be done because the list is empty. Putting the empty case fist should cause the function to terminate with #f before reaching a call to car.

Upvotes: 0

Related Questions