-3

Hi i am learning Scheme new.I have question.Lets think I have defined a function which it adds element to list if it is empty.If there is an element in list and new element is added as second to list and goes like this.For example

>(add a) ; here list is empty
'(a) 
>(add b) ; here a is in the list
'(a b)  
>(add c) ; here a and b is in the list
(a b c)

List is updated like this.How can I write a function like this.I add elements to empty list each time with my code.I mean it is like that with mine.

>(add a)
'(a)
>(add b)
'(b)
>(add c)
'(c)

How can I write the proper code for this purpose ? here is my code

#lang racket
 (define addToList
  (lambda (a b)
    (cond ((null? a) b)
          ((null? b) a)
          ((cons (car a) (addToList (cdr a) b))))))
 (addToList '(1 2 3) '())
leppie
  • 115,091
  • 17
  • 196
  • 297
dymayd
  • 23
  • 1
  • 8

2 Answers2

1

Just like any other language there are two ways to mutate a value. You can mutate what a variable points to (binding) or you can mutate the targeted object by altering parts of the object. The last one requires that the object is not a primitive.

Using variable binding:

#!r6rs
(import (rnrs))

(define lst '())    
(define (add element)
  (set! lst (append lst (list element))) ; adding to front is much cheaper
  lst)

Using mutation:

#!r6rs
(import (rnrs)
        (rnrs mutable-pairs))

(define lst (list 'head))
(define tail lst) ; keep the last cons so we can add O(1)

(define (add element)
  (set-cdr! tail (list element))
  (set! tail (cdr tail))
  (cdr lst))

Your procedure looks more like the functional kind since it's not actually mutating anything, but it would work if you kept the result you got back and fixed the fact that it's not extending the list but adding the element to the tail as a dotted list.

 (define addToList
  (lambda (a b) 
    (cond ((null? a) (list b)) ; result needs to be a list
          ((null? b) a)
          ((cons (car a) (addToList (cdr a) b))))))

 (define lst '())
 (set! lst (addToList lst 1)) 
 (set! lst (addToList lst 2)) 
 (set! lst (addToList lst 3)) 
 lst ; ==> (1 2 3)

I would have written it like this to make it look more like scheme:

(define (add-to-end lst e) 
   (if (null? lst) 
       (list e)
       (cons (car lst)
             (add-to-end (cdr lst) e)))))

Of course adding to front is much cheaper and is done with plain old cons. If you add some elements and actually wanted to add it to end you get the same effect by reversing the list after adding your elements.

VansFannel
  • 45,055
  • 107
  • 359
  • 626
Sylwester
  • 47,942
  • 4
  • 47
  • 79
1

You can't "add" to an empty list in any Lisp dialect, because in all Lisp dialects, the empty list is a special, immutable value.

In Racket, not only is the empty list immutable, but so are all lists. Code that manipulates lists needs to be written in "functional" style to work properly.

"Adding" to a list in the sense of your add function would mean creating a whole new list with one more element and then binding it to the same variable as before:

;;; This implementation of add would behave just like
;;; the examples at the top of your question.
(define add
   (let ((the-list '()))
      (lambda (new-item)
         (set! the-list
               (append the-list (list new-item)))
         the-list)))

The above function runs slower the longer the-list is because it has to copy every element before adding the new one. It is much faster to add to the beginning of a list instead of the end:

(define add
   (let ((the-list '()))
      (lambda (new-item)
         (set! the-list
               (cons new-item the-list))
         the-list)))

For this reason, most Racket programs build their lists backwards, and then use reverse as late as possible to create a forward version of the list.

Throw Away Account
  • 2,593
  • 18
  • 21