0

I am trying to implement a procedure in Scheme that will add an element x at position i to an existing list. This is what I came up with:

(define empty-list '())
(define (add i x L)
  (cond ((null? L) (set! L (list x)))
        ((= i 0)(set! L (cons x L)))
        (else (set! L (cons (car L)
                             (add (- i 1) x (cdr L))))
      )))

(add 0 1 empty-list) -> returns ()
(add 1 2 empty-list) -> returns ()
(add 2 3 empty-list) -> returns ()

The code doesn't update the existing list. However, if I just run (set! empty-list (list 1)) or (set! empty-list (cons 2 empty-list)) it works fine. I am struggling to understand what I am doing wrong.

user53073
  • 51
  • 7
  • Assigning a value to a parameter works exactly like in other languages you're familiar with - it has no effect outside the function. Are you absolutely sure that the intent is for you to mutate the input? It's a very rare thing to do in a Scheme program. – molbdnilo Nov 06 '17 at 08:33

2 Answers2

0

When using set! you are not changing the actual value but you assign the most specific binding with a new value. In JavaScript it works the same:

function add (arr, element) {
  arr = arr.concatenate([element]);
  return arr;
}

const test = [1, 2, 3];
add(test, 4); // => [1, 2, 3, 4]
test;         // => [1, 2, 3]

These kind of procedures in Scheme are usually not mutating. If you remove set! with the value it will return the correct value:

(define (add i x L)
  (cond 
    ((null? L) (list x)) ; might not be at correct position
    ((= i 0) (cons x L))
    (else (cons (car L) (add (- i 1) x (cdr L))))))

(add 1 'b '(a c)) ; ==> (a b c)
Sylwester
  • 47,942
  • 4
  • 47
  • 79
0

In Scheme, like many functional languages, we update the states by calling the recurring function with updated arguments.

(define (add i x l)
  ;; handle base cases outside of recursion, such as
  ;; if the starting list is empty, `i` is disregarded etc.
  (cond [(null? l) (cons x l)]
        [(null? (cdr l))
         (if (<= i 0)
             (cons x l)
             (append l (list x)))]
        [else
         (let recur ([start l] [index 0])
           ;; base case
           (if (= index i)
               (cons x start)
               ;; this is how states are updated
               (cons (car start) (recur (cdr start) (+ index 1)))))]))


;; > (add 3 'newguy '(mary peter nguyen joo kim))
;; '(mary peter nguyen newguy joo kim)
Pandemonium
  • 7,724
  • 3
  • 32
  • 51