Modifying alists

As seen in the previous chapter Scheme provides commands to retrieve elements from association lists although this could also be done using regular list operations. The same is true for adding and setting elements in alists. While it would surely be a good exercise to go through the process in detail you are still lacking some basics, in particular conditionals, so we're sticking to Scheme's dedicated procedures (which you'll be using in general anyway).

Adding an Entry

There is one procedure that simply adds an entry to an association list:

acons <key> <value> <alist>

(as a shortname for “cons an alist”). This creates a pair of the given key and value and “conses” this pair to the alist, returning a new alist with the new key prepended:

guile> (define bool-alist
       '((subdivide . #t)
         (use-color . #f)))

guile> bool-alist
((subdivide . #t) (use-color . #f))

guile> (acons 'debug #f bool-alist)
((debug . #f) (subdivide . #t) (use-color . #f))

guile> bool-alist
((subdivide . #t) (use-color . #f))

From the last expression you can see that the original alist is not modified by this, instead a copy of the combined alist is returned. So if we want to keep the new alist for further use we have to bind it to some other variable (which we'll see in more detail in Binding) or use the following syntax to assign the result to the original variable:

guile> (set! bool-alist
        (acons 'debug #f bool-alist))

guile> bool-alist
((debug . #f) (subdivide . #t) (use-color . #f))

As said above acons simply prepends a new pair, without checking for existing elements with the same key. When you now try to retrieve the entry for such a duplicate entry assq will return the first pair with the matching key:

guile> (set! bool-alist
        (acons 'subdivide #f bool-alist))
guile> bool-alist
((subdivide . #f) (debug . #f) (subdivide . #t) (use-color . #f))

guile> (assq 'subdivide bool-alist)
(subdivide . #f)

As it is rather uncommon to have association lists with non-unique keys Scheme also provides a procedure to add or update a list element:

Adding or Updating List Elements

Scheme provides a set of three procedures to add or update entries in an alist. As with the procedures retrieving elements from alists the three variants refer to three levels of equality that are applied for matching the given pair to potentially existing elements. If the keys in the alist are symbols the procedure to use is

assq-set! <alist> <key> <value>

otherwise you may have to use assv-set! or assoc-set! and - again - familiarize yourself with the different levels of equality in Scheme. (Again: please not the different order of arguments as compared to acons.)

The procedure first checks if the alist already contains an entry with the given key. If it does it replaces the value for that key, so the original alist is updated:

guile> (assq-set! bool-alist 'debug #t)
((subdivide . #f) (debug . #t) (subdivide . #t) (use-color . #f))

guile> bool-alist
((subdivide . #f) (debug . #t) (subdivide . #t) (use-color . #f))

When the procedure does not find the key already present it prepends a new element, just as acons does:

guile> (assq-set! bool-alist 'color red)
((color 1.0 0.0 0.0) (subdivide . #f) (debug . #t) (subdivide . #t) (use-color . #f))

guile> bool-alist
((subdivide . #f) (debug . #t) (subdivide . #t) (use-color . #f))

But please note that - again as with acons in this case the original alist is not updated and a new copy returned instead. So again you have to self-assign the updated list:

guile> (set! bool-alist
        (assq-set! bool-alist 'color red))

guile> bool-alist
((color 1.0 0.0 0.0) (subdivide . #f) (debug . #t) (subdivide . #t) (use-color . #f))

More details and examples can be found on the reference page.

Removing Entries from an alist

The missing third part is how to remove existing elements from alists. Probably you won't be surprised by now that this can be achieved using the procedure

assq-remove! <alist> <key>

and its companions assv-remove! and assoc-remove!. You should understand that what assq-remove! actually does is making sure the given key isn't present in the returned alist. So if you give it a non-existent key the procedure simply does nothing, without any further notification:

``` guile> (assq-remove! bool-alist 'subdivide) ((color 0.0 1.0 0.0) (debug . #t) (subdivide . #t) (use-color . #f))

guile> bool-alist ((color 0.0 1.0 0.0) (debug . #t) (subdivide . #t) (use-color . #f))

(assq-remove! bool-alist 'some-other-key) ((color 1.0 0.0 0.0) (debug . #t) (subdivide . #t) (use-color . #f)) ```

Please not that this time the procedure does modify the alist directly.


Last update: January 31, 2020