sicp-ex-2.23



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


madschemer

why complicate use "and" and output some dummy return value

 (define (for-Each proc items) 
         (if (null? items) 
             #t 
             (and (proc (car items)) (for-Each proc (cdr items))) )) 
  

simv

I think the above solution by madschemer has a bug. If the procedure you pass in returns #f it won't recurse down the list, because the call to "and" will be short-circuited.


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

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))) 


denziloe

Like tyg's answer but using Scheme.

  
 ; Simply iterate with a parameter solely for evaluating the procedure with the current argument. 
 ; In accordance with the function evaluation rule, this parameter will be evaluated each time. 
 ; The parameter is not used in the function body -- it is 'discarded'. 
 ; The initial iteration passes #t to this parameter, which has no effect. 
  
 (define (for-each procedure items) 
   (define (iter items evaluate) 
     (if (null? items) 
       #t 
       (iter (cdr items) (procedure (car items))))) 
   (iter items #t)) 
  


amasad

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

Same idea but an explicit distort function.

  
 (define 
   (for-each procedure list_) 
   (define (distort x) #t) 
   (distort (map procedure list_)) 
 ) 
 (for-each (lambda (x) (newline) (display x)) (list 57 321 88)) 
  


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)  
          ))) 

master

Not really sure if this is an elegant solution but it seems much cleaner than all the other solutions that have been posted. Using the print procedure given as an example, if the input is the empty list then it prints that, otherwise it prints every element of the list excluding the empty list. It works because it first checks whether items is the empty list before reaching ahead to the cdr of items. I don't see any other way to prevent passing a non-pair to cdr and still treat nil as the list terminator.

 (define (for-each proc items) 
   (cond ((null? items) (proc items)) 
         ((null? (cdr items)) (proc (car items))) 
         (else (proc (car items)) (for-each proc (cdr items))))) 

wilson

I use lambda compose two statement in else branch

  
 (define (for-each proc list) 
   (if (null? list) 
       '() 
       ((lambda () 
          (proc (car list)) 
          (for-each proc (cdr list)))))) 

justinm

This solution avoids advanced language features and illustrates a general problem solving approach: First, think of a precondition which makes the problem easy to solve (in this exercise, when the list is nonempty). Then solve the general case by trying to satisfy the precondition.

  
 (define (for-each proc list) 
   ; precondition: list is nonempty.  
   (define (for-each-nonempty list) 
     (proc (car list)) 
     (if (null? (cdr list)) 
         '() 
         (for-each-nonempty (cdr list)))) 
   ; general case: ensure precondition. 
   (if (null? list) 
       '() 
       (for-each-nonempty list)))