user3058606
user3058606

Reputation: 9

What does (cons? list-name) do?

I was wondering what (cons? list-name) does. Does it just check that list-name is not a non-empty list? Is it just like the opposite of (empty? list-name)? If so, then is it not better to just say (empty? list-name) and then say else instead of cons?? For example:

(define (f list-name)
   (cond
     [(empty? list-name) empty]
     [(cons? list-name) "do something]))

Upvotes: 0

Views: 353

Answers (2)

daniel gratzer
daniel gratzer

Reputation: 53911

cons? checks whether the value is a cons cell, e.g., something that's (cons foo bar) for some foo and bar.

> (cons? 1)
#f
> (cons? '())
#f
> (cons? (list 1 2 3))
#t
> (cons? (cons 1 2))
#t

If (cons? a) is true, then it is safe to use car and cdr on a.

This isn't the opposite of empty? since empty? is true if and only if the argument is the empty list, so (empty? 1) == (cons? 1) == #f.

Sidenote: Please don't put PLEASE HELP!! or similar in your question titles, everyone here is happy to help, but it's a bit obnoxious to read. Just something to keep in mind in the future. Welcome to SO.

Upvotes: 1

Joshua Taylor
Joshua Taylor

Reputation: 85913

jozefg's answer is right in pointing out that (cons? x) is not the same as (not (empty? x)), in general, because there are things (e.g., numbers) that are neither cons cells nor the empty list.

However, your variable was list-name, so you may have some reason to expect that its value is, in fact a list. A list, in Scheme, is either:

  • the empty list; or
  • a cons cell whose car is the first element of a list and whose cdr is the rest of the list.

Because of this, if you're writing a function that requires a list be passed in, then it does make sense to simply check for the trivial case (the empty list) with empty?, and to assume, since you've required a list, that anything that doesn't match that case is a cons cell on which you can call cdr and cdr. This is because while

(cons? x) == (not (empty? x))

is not true of values in general, it is true for lists. That is, if you already know that lst is a list, then

(cons? lst) == (not (empty? lst))

is true. There are a number of functions that do the same thing when we're talking about lists and cons cells. E.g., empty? and null? do the same thing, but they signal a slightly different intent on the part of the programmer. Similarly, car and cdr do the same thing as first and rest, but car and cdr signal that you might be treating something as a pair of two things, whereas first and rest clearly signal the intent that you're working with a list.

Your code, since it seems to expect a list, should probably be the following, since, for a list, if it's not the empty list, it must be a cons.

(define (f lst)
   (cond
     [(empty? lst) empty]
     [else "do something]))

More generally, the code you write should depend on what kind of input you expect. E.g., in the first case, it's fine to check for empty, and assume a cons otherwise, because you're expecting a list. In the second case, you have to check for all the different kinds of things you might see.

(define (frob-list lst)
   (cond
     [(empty? lst) empty]  ; arg is ()
     [else ...]))          ; arg is (x . y)

(define (frob-object obj)
   (cond
     [(null? obj) ...]     ; arg is ()
     [(cons? obj) ...]     ; arg is (x . y)
     [(number? obj) ...]   ; arg is r
     ...                   ; arg is ...
     [else ...]))          ; else ...

Upvotes: 1

Related Questions