Are expressions such as (set! c (cons 3 c)) the way to add an item to a list?

StackOverflow https://stackoverflow.com/questions/8975104

  •  18-04-2021
  •  | 
  •  

Domanda

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?

È stato utile?

Soluzione

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.

Altri suggerimenti

(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)))))

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?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top