sicp-ex-4.8



<< Previous exercise (4.7) | Index | Next exercise (4.9) >>


meteorgan

  
  
 (define (named-let? expr) (and (let? expr) (symbol? (cadr expr)))) 
  
 (define (named-let-func-name expr) (cadr expr)) 
  
 (define (named-let-func-body expr) (cadddr expr)) 
  
 (define (named-let-func-parameters expr) (map car (caddr expr))) 
  
 (define (named-let-func-inits expr) (map cadr (caddr expr))) 
  
 (define (named-let->func expr) 
     (list 'define  
           (cons (named-let-func-name expr) (named-let-func-parameters expr)) 
           (named-let-func-body expr))) 
  
 (define (let->combination expr) 
     (if (named-let? expr) 
         (sequence->exp 
           (list (named-let->func expr) 
                 (cons (named-let-func-name expr) (named-let-func-inits expr)))) 
         (cons (make-lambda (let-vars expr) 
               (list (let-body expr))) 
               (let-inits expr)))) 
          

karthikk

While the above should work, the problem with doing it with define is that it raises the possibility of nameclash issues, as define directly installs the name of the lambda in the named let into the current frame of the environment. The other possibility, which allows greater control of scope is to do it with the usual let, adding an arbitrary binding for var which is then reassigned in the body of the let expression (with a set! command) to the needed lambda before anything else is evaluated...


inchmeal

One approach where name of procedure is only available inside the body:

  
 (define (let? exp) (tagged-list? exp 'let)) 
 (define (let-has-name? exp) (symbol? (cadr exp))) 
 (define (let-name exp) (cadr exp)) 
 (define (let-vardefs exp) 
   (if (let-has-name? exp) 
       (caddr exp) 
       (cadr exp))) 
 (define (let-body exp) 
   (if (let-has-name? exp) 
       (cdddr exp) 
       (cddr exp))) 
 (define (let->combination exp) 
   (let ((res (fold-right 
               (lambda (new rem) 
                 (cons (cons (car new) (car rem)) 
                       (cons (cadr new) (cdr rem)))) 
               (cons '() '()) 
               (let-vardefs exp)))) 
     (let ((vars (car res)) 
           (vexps (cdr res))) 
       (define proc (make-lambda vars (let-body exp))) 
       (if (let-has-name? exp) 
           ;;create a lambda with no args containing: 
           ;;(i) definition of the actual lambda(proc) 
           ;;(ii) invocation of proc with supplied expressions. 
           ;;finally create application for this no argument lambda. 
           (cons 
            (make-lambda '() 
                         (list (list 'define (let-name exp) proc) 
                               (cons (let-name exp) vexps) 
                               )) 
            '()) 
           (cons proc vexps) 
       )))) 

I'm with this approach, that the effect of scoping can be achieved by defining a lambda with no args and calling it immediately.