user1786512
user1786512

Reputation: 89

Defining a Scheme function

So i have been stuck trying to learn this Scheme language that i heard about from a friend of mines. What he said i should do is start small and work my way up to truly understanding it. So after reading a textbook that he had that discusses Scheme programming briefly, i am a little puzzled myself on how it works.

So pretty much what i am trying to ask is that if i wanted to add a definition to a function called, let's say 'evens' from a couple of list i have define:

(DEFINE list0 (LIST 'j 'k 'l 'm 'n 'o 'j) )
(DEFINE list1 (LIST 'a 'b 'c 'd 'e 'f 'g) )
(DEFINE list2 (LIST 's 't 'u 'v 'w 'x 'y 'z) )
(DEFINE list3 (LIST 'j 'k 'l 'm 'l 'k 'j) )
(DEFINE list4 (LIST 'n 'o 'p 'q 'q 'p 'o 'n) )
(DEFINE list5 '((a b) c (d e d) c (a b) )
(DEFINE list6 '((h i) (j k) l (m n)) )
(DEFINE list7 (f (a b) c (d e d) (b a) f) )

such that it does like the task below: evens

which I have already created a adder function which i believe is to be:

(DEFINE (adder lis)
    (COND
        ((NULL? lis) 0)
        (ELSE (+ (CAR lis) (adder (CDR lis))))
))

what might the definition for even be if i would want it to do like the task below:

EVENS: (evens 1st) should return a new list, formed from the the even numbered elements taken 1st.

(evens '(a b c d e f g))
which would/should return:
(b d f)

and:

(evens (LIST 's 't 'u 'v 'w 'x 'y 'z))
which would/should return:
(t v x z)

and:

(evens '(f (a b) c (d e d) (b a) f) )
which would return:
((a b) (d e d) f)

and both (evens '()) and (evens '(a))

would return the empty list.

I have been going through trail in error to practice but i am totally lost. Thanks in advance

Okay, I think that i have come up with a recursive function to my example that i have been trying to work out:

 (define mylist '(1 2 3 4 5 6 7))
 (define (evens lst)
 (define (do-evens lst odd)
     (if (null? lst)
 lst
     (if odd
         (do-evens (cdr lst) #f)
         (cons (car lst) (do-evens (cdr lst) #t)))))
         (do-evens lst #t))

any thoughts?

Upvotes: 4

Views: 3920

Answers (3)

duthen
duthen

Reputation: 908

What about this:

(define (evens l)
  (cond
   ((null? l) '())
   ((null? (cdr l)) '())
   (else (cons (cadr l) (evens (cddr l))))))

But I like the evens and odds answer!

Upvotes: 0

itsbruce
itsbruce

Reputation: 4843

OK, so to do a recursive function that iterates over a list, picking some elements to return and not others, the basic pattern is going to be

(define (recur l)
  (cond
    ((null l) '())
    ((??????) (cons (car l) (recur (cdr l))))
    (else (recur (cdr l)))))

What that does is

  1. Is the list null? Return null.
  2. If the list is not null, should we be keeping the first item on the list? Ok, let's keep it and add it to whatever (recur (cdr l)) returns
  3. Otherwise, just return whatever recur (cdr l) returns.

What I hope this makes clear is that a simple recursive list function only looks at the first element of the list, determines what do do with that and then calls itself again with the remainder of the list. Recursion is, in one sense, a way of simplifying computation by only dealing with the first part of the data and leaving another function to worry about the rest of the data (the other function is actually the same function you called the first time, but try not to worry about that). For example, a recursive function which only returned the items which were even numbers could look like this:

(define (even-numbers l)
  (cond
    ((null? l) '())
    ((even? (car l)) (cons (car l) (even-numbers (cdr l))))
    (else (even-numbers (cdr l)))))

That said, your case is slightly more complex; you need to drop the first element and then, in each successive call to the function, do the opposite of the last call.

One way to to this is to pass on a boolean status, flipping it each time. Note that since the evens function doesn't take state, you have to define a different internal function and recur on that:

(define (evens l)
  (let loop ((lst l) (keep #f))
      (cond
         ((null? lst) '())
         ((eq? keep #t) (???????)
         (else (loop (cdr l) #t)))))

You should be able to work out what goes in (???????) for yourself, given the previous examples. I've done a little too much work for you, I think.

Another way to do this is with mutually recursive functions evens and odds. Consider that

  1. evens is a function that throws away the first element and then works through the list, each time doing the opposite (keep or discard) of what it did last time.
  2. odds is a function that keeps the first element and then works through the list, each time doing the opposite (keep or discard) of what it did last time.

This means that you could define

  1. evens as a function that ignores the first element and simply calls odds on the remainder of the list.
  2. odds as a function that keeps the first element, calls evens on the remainder of the list and cons-es the first element onto the beginning of the result.

That would look something like

(define (evens l)
  (cond
    ((null? l) '())
    (else (odds (??????)))))

(define (odds l)
  (cond
    ((null? l) '())
    (else (cons (car l) (evens (??????))))))

Hopefully, this makes some sense.

If you really want to understand recursion in Scheme, buy a copy of "The Little Schemer" and start working through it.

Upvotes: 2

Dima
Dima

Reputation: 39389

First of all, the adder function has nothing to do with your question, right?

Think about the evens function. You have already said that (evens '()) and (evens '(a)) should return the empty list. What should (evens '(a b)) return? What about (evens '(a b ...))? Do you see how to set up the recursion?

Upvotes: 2

Related Questions