Append! in Scheme?

append, scheme

Solution

Mutation, though allowed, is strongly discouraged in Scheme. PLT even went so far as to remove `set-car!` and `set-cdr!` (though they "replaced" them with `set-mcar!` and `set-mcdr!`). However, a spec for `append!` appeared in SRFI-1. This `append!` is a little different than yours. In the SRFI, the implementation may, but is not required to modify the cons cells to append the lists.

If you want to have an `append!` that is guaranteed to change the structure of the list that's being appended to, you'll probably have to write it yourself. It's not hard:

(define (my-append! a b)
  (if (null? (cdr a))
      (set-cdr! a b)
      (my-append! (cdr a) b)))

To keep the definition simple, there is no error checking here, but it's clear that you will need to pass in a list of length at least 1 as `a`, and (preferably) a list (of any length) as `b`. The reason `a` must be at least length 1 is because you can't `set-cdr!` on an empty list.

Since you're interested in how this works, I'll see if I can explain. Basically, what we want to do is go down the list `a` until we get to the last `cons` pair, which is `(<last element> . null)`. So we first see if `a` is already the last element in the list by checking for `null` in the `cdr`. If it is, we use `set-cdr!` to set it to the list we're appending, and we're done. If not, we have to call `my-append!` on the `cdr` of `a`. Each time we do this we get closer to the end of `a`. Since this is a mutation operation, we're not going to return anything, so we don't need to worry about forming our modified list as the return value.

Problem

I'm learning R5RS Scheme at the moment (from PocketScheme) and I find that I could use a function that is built into some variants of Scheme but not all: Append! In other words - destructively changing a list. I am not so much interested in the actual code as an answer as much as understanding the process by which one could pass a list as a function (or a vector or string) and then mutate it. example: ``` (define (append! lst var) (cons (lst var)) ) ``` When I use the approach as above, I have to do something like `(define list (append! foo (bar))` which I would like something more generic.

Original source