user7630822
user7630822

Reputation: 51

accessing an element in a list in Scheme

I have to write a function in scheme to access the element 'a' in the following list. '(1 (2 a 4 5))

I wrote

(car (cdr (cdr '(1 (2 a 4 5)))))

but i get error

"car: contract violation
  expected: pair?
  given: '()"

How do i fix this to work ?

Upvotes: 1

Views: 694

Answers (3)

Sylwester
Sylwester

Reputation: 48775

(1 (2 a 4 5) in dot notation is:
(1 . ((2 . (a . (4 . (5 . ())))) . ()))

For every pair (a . d) you use car to get the first and cdr to get the second.
If you look at the dot notation you need to:
pass d to get ((2 . (a . (4 . (5 . ())))) . ()),
then a to get (2 . (a . (4 . (5 . ())))),
then d to get (a . (4 . (5 . ()))) and
then a to get a.

You order them from the end to beginning so
(car (cdr (car (cdr '(1 (2 a 4 5))))) or if you just look at the letters again and add c in the beginning and r in the end it's:
(cadadr '(1 (2 a 4 5)))

It's very important to know that (1 2 3 4) is (1 . (2 . (3 . (4 . ())))) and that if you want the 3rd element it's the car of the cddr; alternatively caddr.
Read the a and d from right to left while looking at the dot notation.
To become a native speaker of cxr you need to do a lot of these.
How would the dot notation of ((1) (2)) look like? How do you access 2?

And of course, the pair (1 . 2) can be made with (cons 1 2).

Upvotes: 1

querist
querist

Reputation: 654

Proceeding from @soegaard's response... The thing that is causing the problem is the fact that you have a list contained in a list.

starting with (car (cdr '(1 (2 a 4 5)))), which is '(2 a 4 5), you now need to pull the second item from that list, which you can do with the single cadr procedure or you can nest them, producing (car (cdr (car (cdr '(1 (2 a 4 5))))))

As soegaard explained, there is an "invisible" empty list in there, which explains why you need (car (cdr '(1 (2 a 4 5)))) to get the list.

Remember, '(2 a 4 5) is a list, so you need to treat it as a list. Get the cdr and then pull the car from it.

As @Sylwester noted, you can combine the letters to form compound names. Racket supports up to four layers, so you can create the one you need (barely) and obtain the same result with (cadadr '(1 (2 a 4 5))).

Remember the "invisible" empty list. That seems to be what was tripping you up.

Upvotes: 0

soegaard
soegaard

Reputation: 31145

Let's first look at (2 a 4 5). This is a list of four elements: 2, a, 4, and, 5. Such a list value can be constructed using the function cons :

(cons 2 (cons 'a (cons 4 (cons 5 '()))))

where '() is the empty list.

The list (1 X) can be created like this:

(cons 1 (cons X '()))

Combining the second expression with the first expression we see that

(cons 1 (cons (cons 2 (cons 'a (cons 4 (cons 5 '())))) '()))

will construct the list (1 (2 a 4 5)).

Now we are ready to see what happens:

> (cdr (cons 1 (cons (cons 2 (cons 'a (cons 4 (cons 5 '()))))  ; the car
       '())))                                                  ; the cdr
(cons (cons 2 (cons 'a (cons 4 (cons 5 '())))) '())            ; 

> (cdr (cdr (cons 1 (cons (cons 2 (cons 'a (cons 4 (cons 5 '())))) '())))
= (cdr   (cons (cons 2 (cons 'a (cons 4 (cons 5 '()))))  ; the car
               '())                                      ; the cdr
= '()

> (car (cdr (cdr (cons 1 (cons (cons 2 (cons 'a (cons 4 (cons 5 '()))))
                       '()))))
= (car '())
= ERROR

Try this in a repl and then see if you can figure out how to proceed:

(car (cdr  the-list-expression ))

Upvotes: 0

Related Questions