One last use of set!: Imperative programming:
In scheme, the fundamental unit of computation is function-call. (A functional language)
In imperative langauges (JAM, C, Java), the fundamental unit is assign-to-variable (and sequence), with a background emphasis on calling functions.

(define N 30)
(define sum-so-far 0)
(fori= 0 N
       (lambda (i) (set! sum-so-far (+ sum-so-far i))))
Or even:
(define N 30)
(define sum-so-far 0)
(define i 0)

(define (dostuff)
  (if (>= i N)
      (void)
      (begin (set! sum-so-far (+ sum-so-far i))))
             (set! i (add1 i))
             ; A common bug: reversing the order of the add1 and adding i.
             (dostuff)))
To process a list, imperatively:
(define meal (list 'yam 'cran 'flan))
(define list-remaining meal)
(while (lambda () (not (empty? (list-remaining))))
       (lambda () (begin (set! list-remaining (rest list-remaining))
                         (printf "Care for some more ~s?~n" (first list-remaining))))

; OR

(define list-remaining meal)
(define (dolist)
  (if (empty? (list-remaining)))
      (void)
      (begin (set! list-remaining (rest list-remaining))
             (printf "Care for some more ~s?~n" (first list-remaining))))
Here, really the set! is just being used to control the loop, and it's not really necessary:
(while  cons?   meals    rest
        (lambda (list-remaining)
           (printf "Care for some more ~s?~n" (first list-remaining))))

How would we write append!, imperatively? It takes two lists and modifies the first so that it includes the second.

Remember, to start with examples. Draw pictures! (What do you realize must be the case? We'll think about fixing that later.)

You can write this imperatively or not, w/ or w/o a for-loop.

;; imperatively, w/o for-loop.
(define (append! list1 list2)
  (local [(define list1-remaining list1)  ;"l1r"
          (define (do-append!)
            (if (length1? list1-remaining) 
                (set-list-rest! list1-remaining list2)
                (begin (set! list1-remaining (rest list1-remaining))
                       (do-append!))))]
    (do-append!)))
This version has a big problem (as mentioned in lecture). Here's a functional version, w/o a for-loop:
(define (append! list1 list2)
  (cond [(empty? list1) ..]
        [(length1? list1) (set-list-rest! list1 list2)]
        [else (append! (rest list1) list2)]))

Note in all these examples, the imperative version is not any easier than the functional version.


Side topics, for fun: (See help-desk for details)


The complete code from lecture:
;;; Misc helper functions.
(define identity (lambda (x) x))
(define (length1?  l) (and (cons? l) (empty? (rest l))))
(define (length>1? l) (and (cons? l) (cons?  (rest l))))



;;; Several loop variants.

;; An imperative version of "fori="
;;
;; Call body! on each integer in [strt,stop).
;;
(define (fori=-i strt stop body!)
  (cond [(>= strt stop) (void)]
        [else (begin (body! strt)
                     (fori=-i (add1 strt) stop body!))]))

;; An accumulator-version of "fori="
;;
;; Call body on each intgeter in [strt,stop)
;; also passing in the result so-far.
;;
(define (fori=-a strt stop body so-far)
  (cond [(>= strt stop) so-far]
        [else (fori=-a (add1 strt) stop body (body strt so-far))]))


;; An imperative version of "while".
;;
;; while continue? (applied to 0 args) returns true,
;; repeatedly call body! (applied to 0 args).
;; 
(define (while-i continue? body!)
  (cond [(not (continue?)) (void)]
        [else (begin (body!)
                     (while-i continue? body!))]))

;; An accumulator version of "while".
;;
;; While continue? (applied to so-far) returns true,
;; repeatedly call body (applied to so-far), using
;; its return as the next value of so-far.
;;
(define (while-a init continue? next so-far body)
  (cond [(not (continue? init)) so-far]
        [else (while-a (next init) continue? next (body init so-far) body)]))


;;; Examples of suing the loops for a trivial problem: compute 17+16+...+1.
;;; (Well, the for-loops add upward, and the while loops downward, as written.)

(define N 18)


; Using a for-loop, accumulator style:
;
(fori=-a 0 N + 0)

; Using a for-loop, imperative style:
;
(local [(define sum-so-far 0)]
  (begin (fori=-i 0 N (lambda (i) (set! sum-so-far (+ i sum-so-far ))))
         sum-so-far))


; Using a while-loop, accumulator style:
;
(while-a (sub1 N) positive? sub1 0 +)


; Using a while-loop, imperative style:
;
(local [(define sum-so-far 0)
        (define i (sub1 N))]
  (begin (while-i (lambda () (positive? i))
                  (lambda () (begin (set! sum-so-far (+ i sum-so-far))
                                    (set! i (sub1 i)))))
         sum-so-far))


;;; Another example of while-a

; Return a singleton list of the input's last element,
; or return false if given empty.
;
(define (last a-list)
  (while-a a-list cons? rest false (lambda (l so-far) l)))

(last '(fee fie fo fum))  = '(fum)
(last empty) = false




;;;;;;;; imperative programming:

;; calculate 0+1+2+...+29.
;;
(define sum-so-far 0)
(fori=-i 0 N
         (lambda (i) (set! sum-so-far (+ sum-so-far i))))
sum-so-far

; Really, should wrap i inside a lambda,
; and actually return the value (rather than just storing it in sum-so-far).



;; Same thing again, w/o the loop construct
;; (since really we can use set! to modify the loop variable).
;; Just to see how it'd be done:
;;
(define N 30)
(define sum-so-far 0)
(define i 0)

(define (dostuff)
  (if (>= i N)
      (void)
      (begin (set! sum-so-far (+ sum-so-far i))
             (set! i (add1 i))
             ; A common bug: reversing the order of the add1 and adding i.
             (dostuff))))
sum-so-far
;
; Note that this code isn't as structured as the previous:
; the loop is muddled in with the rest of the code,
; and the looping mechansism paid no heed to the shape of the data.
; Such loops for processing over lists are more awkward.



;;;;;; interative programming on lists:

(define meal (list 'yam 'cran 'flan))
(define dessert (list 'cobbler 'pie))


;; Print out each element, using a imperative while-loop:
;
(define list-remaining meal)
(while-i (lambda () (not (empty? list-remaining)))
         (lambda () (begin 
                      (printf "Care for some more ~s?~n" (first list-remaining))
                      (set! list-remaining (rest list-remaining)))))


;; For comparison: the accumulator version of the same:
;;
(while-a  meal    cons?   rest  (void) ; No value we're accumulating.
          (lambda (list-remaining so-far)
             (printf "Care for some more ~s?~n" (first list-remaining))))






;; Same thing, but w/o the while-loop (again, we're essentially
;; doing the looping manually ourselves).

(define list-remaining meal)
(define (dolist)
  (if (empty? list-remaining)
      (void)
      (begin 
        (printf "Care for some more ~s?~n" (first list-remaining))
        (set! list-remaining (rest list-remaining)))))








;;;;;;;; append!
(define set-list-rest! set-cdr!)


;; Imperative version, w/o a loop.
;;
(define (append!-v1 list1 list2)
  (local [(define list1-remaining list1)  ;"l1r"

          ; In essence, set up our own loop construct:
          (define (do-append!)
            (if (length1? list1-remaining) 
                (set-list-rest! list1-remaining list2)
                (begin (set! list1-remaining (rest list1-remaining))
                       (do-append!))))]
    (do-append!)))
;
; This above version has a big problem: 
; blows up if we pass in "empty" for list1.  Oops.


; We stop to think,
; and realize that append! CANNOT work when list1 is empty:
; set-struct! doesn't help, because empty isn't a structure 
; (just a simple value);
; set! doesn't help, because set! can affect (say) "list1",
; but inside the function we don't know what placeholder
; was used for the list (if any), and we can't change it).
; 
; (java has the same problem, or any language w/o pass-by-reference.)
; One solution: realize that if we want a container/list which
; is mutable even when empty, make a data-def'n where even the
; empty list is a structure.
; Usual approach: make a structure with one element -- the regular
; 'ol scheme list. [this takes a while to think about and understand]

(append!-v1 meal dessert)
meal

;; WARNING: calling    (append!-v1 meal dessert) again will have 
;; weird consequences, since meal and dessert already share structure.



; Here's a functional version, w/o a for-loop:
;
;; append!: cons, list --> (void)
;; SIDE-EFFECT modify list1 to include all list2's contents.
;; Note tha tlist1 must be a cons, not empty, for this to work.
;;
(define (append!-v2 list1 list2)
  (cond [(length1? list1) (set-list-rest! list1 list2)]
        [else (append!-v2 (rest list1) list2)]))

; To think about: how to wrap a function around this, so that
; we can return the list we just modified?

(append!-v2 meal (list 'peaches 'jello))
meal



;;;;;;;; imperatively, w/ a loop:

(define (append!-v3 list1 list2)
  (local [(define list1-remainder list1)]
    (begin
      (while-i (lambda () (length>1? list1-remainder))
               (lambda () (begin (set! list1-remainder (rest list1-remainder)))))
      (set-list-rest! list1-remainder list2))))

(append!-v3 meal (list 'derby 'pie))
meal


;;;;;;;; functionally, w/ a loop:


(define (append!-v4 list1 list2)
  (set-list-rest! (while-a list1 length>1? rest list1 (lambda (l so-far) l))
                  list2))

; Here the loop-index (successive rests of list1)
; is also what we want the body to return, so that's repeated.

(append!-v4 meal '(toothpick))
meal