sicp-ex-2.23


 (define (for-each proc items) 
   (let ((items-cdr (cdr items))) 
     (proc (car items)) 
     (if (not (null? items-cdr)) 
         (for-each proc items-cdr) 
         true))) 

<< Previous exercise (2.22) | Index | Next exercise (2.24) >>


sritchie

  
  
  
 ;; I didn't find that any of the other implementations here 
 ;; supported the null list as input; here's my fix. 
 ;; for-each 
  
 (define (for-each proc list) 
   (cond 
    ((null? list) #t) 
    (else (proc (car list)) 
          (for-each proc (cdr list))))) 
  


jz

  
 ;; for-each 
  
  
 ;; The below didn't work ... basically, I needed some kind of block 
 ;; structure, since if has the form (if (test) true-branch 
 ;; false-branch).  I needed to have true-branch execute the proc, then 
 ;; call the next iteration of for-each, and the only way I knew how to 
 ;; do that was with brackets ... but of course that doesn't work, as 
 ;; the interpreter tries to apply the result of the first proc call as 
 ;; a function to the rest. 
 (define (for-each proc items) 
   (if (not (null? items)) 
       ((proc (car items)) 
       (for-each proc (cdr items))))) 
  
 (for-each (lambda (x) (newline) (display x)) (list 1 2 3 4)) 
  
  
 ;; This one works. 
 ;; Moral: cond is better for multi-line branches. 
 (define (for-each proc items) 
   (cond ((not (null? items)) 
          (proc (car items)) 
          (for-each proc (cdr items))))) 
  
  


tyg

  
  
  
 ;;; First, I'm sorry for using common lisp. 
 ;;; This is an easy but funny problem, At a first glance, I think I need some 
 ;;; block structure such as cond, progn, etc., in fact, you can use function 
 ;;; argument eval rule to avoid using them at all. I think this solution has  
 ;;; more 'functional style'. 
  
  
 (defun for-each (f items) 
   (labels ((iter (action lst) 
              (if (null lst) 
                  action 
                  (iter (funcall f (car lst)) (cdr lst))))) 
     (iter nil items))) 

amasad

  
 ; :) 
  
 (define (for-each proc items) 
   (map proc items) 
   #t) 
  

AMS

The above solution by amasad is incorrect as MAP is different to FOR-EACH. Map will create a LIST of the results whereas we don't want the output of For-each to create a list, just to apply the specified procedure to each of the list elements.

The solution by amasad is perfectly fine. It returns true, it doesn't matter if internally it "creates a list" or whatever. In fact, I'd say this'd be fine too:

 (define for-each map) 

as the exercise states that the result can be arbitrary, so it can arbitrarily be the list of items in the list applied to the given procedure.

I think this solution is incorrect not because of AMS's reason, but rather because the implementation of MAP can vary, and it isn't guaranteed that the procedure that is given to MAP will be applied left-to-right (see this in the R5RS specification: "The dynamic order in which proc is applied to the elements of the lists is unspecified").




wbooze

  
  
  
 ;;; i did the same with common-lisp 
 ;;; it pretty much matches the first scheme form on this page tho! 
  
 (defun for-each (proc items) 
   (if (null items) 
       nil 
       (apply proc (car items) nil)) 
   (if (not (null (cdr items))) 
       (for-each proc (cdr items)))) 
  

anonymous

  
  
  
 ;; Another way to use if instead of cond. 
 ;; We just wrap the multiple statements in a let. 
 ;; From: http://wiki.drewhess.com/wiki/SICP_exercise_2.23 
  
 (define (for-each proc items) 
   (if (not (null? items)) 
       (let () 
         (proc (car items)) 
         (for-each proc (cdr items))))) 

you can use "begin" instead of "let ()"

  
 (begin 
   (...) 
   (...)) 


coriolis

  
  
 (define (for-each unary-proc seq) 
        (if (null? seq) 
            (newline) 
            (unary-proc (car seq)) (for-each unary-proc (cdr seq)) ) )  
  
  

erik

This was my solution, kind of weird but it worked on the example in the book.

  
 (define (for-each f items) 
   (define (iter f items . cur) 
     (if (null? items) 
         #t 
         (iter f 
               (cdr items) 
               (f (car items))))) 
   (iter f items)) 
  

Tom

May be not so concise as other solutions. But without let and other advanced features, very straightforward. The "block structure" mentioned by jz can be achieved by a function, as we have learnt from previous chapter (procedural abstraction).

 (define (for-each proc items) 
   (if (null? items) 
       nil 
       ((lambda (li) (proc (car li)) (for-each proc (cdr li))) items))) 

And in the first answer, do not see why a return value true is necessary. The following one will not return or print a #t as the end.

  (define (for-each-an1 proc items)  
    (let ((items-cdr (cdr items)))  
      (proc (car items))  
      (if (not (null? items-cdr))  
          (for-each-an1 proc items-cdr)  
          )))