2

Scheme has set-car! and set-cdr!, but no set-cons! .

Are expressions such as

(set! c (cons 3 c))

which places the element 3 on the list c, the proper/only/best/usual way to modify a list?

drb
  • 728
  • 8
  • 21
  • "cons is the pair constructor procedure": The Scheme Programming Language, 3rd ed., page 133. http://www.scheme.com/tspl3/objects.html#./objects:h1 – drb Jan 24 '12 at 16:11

3 Answers3

5

(set! c (cons 3 c))

Well, let's be clear what this expression does:

  • set! takes a variable as its first argument and an expression as the second argument. It evaluates the second argument, and assigns the value to the variable.
  • cons takes a value and a list, and produces a list with the given value as its head, and the given list as its tail.

So, (set! c (cons 3 c)) constructs a list with 3 as the head and c as the tail, and assigns that list as the value of c. This change is only visible to code that accesses the same binding of c—if there are other variables or object fields that refer to the original list, they still refer to that original list.

This can be loosely described as "adding an item to a list" in some contexts, but this is a loose description, because you're not taking an existing list and modifying it to have a new item; rather, you're creating a list with a new initial item and the original list as its tail, and changing some (but maybe not all) references to the old list to point to the new one.

There are two main things I can think off right away that also could count as "adding an item to a list":

  • Modifying the structure of an existing list to add a new pair somewhere in the middle or the end. If you're really strict about terminology, this is the only true case of "adding an item to a list."
  • Consing an item to the front of a list and returning it to the caller or passing it as an argument to another function (without set!). This is even looser language than your example—but it's also the most common case!

Example of the first:

(define (insert-at-second-position! item list)
  (set-cdr! list (cons item (cdr list))))

Example of the second:

(define (list-copy xs)
  (if (null? xs)
      '()
      ;; We call list-copy recursively on the tail, and "add an item"
      ;; at the front:
      (cons (car xs)
            (list-copy (cdr xs)))))
Luis Casillas
  • 29,802
  • 7
  • 49
  • 102
  • Thank you for this thorough answer. As is often the case, imprecision of expression actually shows an imprecision in thought or conception, as I do above. – drb Jan 24 '12 at 13:33
1

That is the correct way to modify the list c. But such usage is rare. Perhaps you could tell us more about what you are trying to do.

user448810
  • 17,381
  • 4
  • 34
  • 59
  • I am learning the language. It took me some minutes to understand a small program I wrote wasn't working because (cons item list) does not modify the list (as I unthinkingly assumed), but returns the result of placing item on the list. – drb Jan 23 '12 at 16:38
  • 4
    Few Scheme programs proceed by modification. You will need to change the way you think about programming if you want to use Scheme. The book _The Little Schemer_ by Friedman and Felleisen is a good introduction to the Scheme way of thinking. – user448810 Jan 23 '12 at 17:12
0

You need to know about type constructors, modifiers and accessors.

Pairs are CONStructed with cons, which is a procedure of 2 arguments, the first argument (the car) is the first element of the pair and the second argument (cdr) is the second element of a pair. Proper lists require it's cdr to be a null-terminated list. Otherwise, it is only a pair.

Pair selectors, (car and cdr) take one argument, a CONStructed list, and either extracts the first (using car) or the rest (using cdr) of is pair argument.

Modifiers (setters) take 2 arguments: an existing CONStruct (a pair, a car of a pair, and basically anything that has been constructed) and replaces the selected construct with the value of its second argument.

(set-car! (cons 'a (cons 'b '())) 'c) ;; is the same as
(set! (car (cons 'a (cons 'b '()))) 'c)

Got it?