0
votes

I'm very new to scheme and am trying to figure out how to define a function that tests if the parameter to that function is a list, where being a proper list doesn't matter.

I've discerned that I need to check if the argument is either the empty list or a pair. I have the empty list case working fine, but I'm not sure how to check for the pair. I'm just coming off working with prolog, so my initial thought was to do something like this:

(define list?
  (lambda (ls)
    (if (or (eq? ls (quote())) 
            (cons(car(ls) cdr(ls)))) 
        true false)))

My thinking was that if scheme could car and cdr the parameter, then it must be a pair, and it would return true. Otherwise it would just fail.

However, passing the argument '(1 2) yields this result:

(list? '(1 2))
. . application: not a procedure;
expected a procedure that can be applied to arguments
   given: (1 2)
   arguments...: [none]

I don't really understand what's going on here. Additionally, I feel like my thinking as to how to make this function is flawed, but I don't really know how to correct it.

EDIT: Is the issue that (if .....) is looking for a boolean from cons?

1
tfw when I find out there are pair? and null? functions in scheme - Christian Baker
Yep, that's the right way to solve the problem, but there are some additional points to consider. Please see my answer. - Óscar López

1 Answers

0
votes

You have right idea! But the main reason why your code is not working is that on fourth line you have wrong brackets. This is right transcription of your code:

(define list?
  (lambda (ls)
    (if (or (eq? ls (quote())) 
            (cons (car ls) (cdr ls))) 
        #t #f)))

But in my opinion this solution is bad for these reasons:

  1. If you supply improper list to this procedure it will end by an error when trying to do car or cdr. For example: (1 2 3 . 4) will end by an error.

  2. In Scheme you have to use literals #t and #f to denote true and false.

  3. Cons always end by "true"

  4. It will not check entire list.

I would write that procedure like this:

(define list?
  (lambda (ls)
    (if (null? ls)
        #t
        (and (pair? ls)
             (list? (cdr ls))))))

Lets try this on an example: (3 . 4). It is just pair - not a list.

  1. The ls is (3 . 4). Is it null? No, then continue to second if branch.

  2. Is it pair? Yes - continue in and and recursively call list? with 4

  3. The ls is 4. Is it null? No. Again, continue to second branch.

  4. Is it pair? No! Procedure returns #f