[plt-scheme] Re: trying not to use eval - in a define-syntax

From: Jim Witte (jswitte at bloomington.in.us)
Date: Tue Oct 29 21:49:19 EST 2002

>> I want to take the value from a variable and use it as a procedure
>> name,   and have it be evaluated.  I remember running across some
>> advice in a text that using eval was *BAD*, but I am stumped on how

   I want to make a 'foreach' syntax which would function like map, 
except that it would (1) go in order (instead of arbitrary), (2) pass 
in the reference for each element the function is currently processing, 
and (3) be able to pass in an arbirary number of 'static' variables 
that don't change from one invocation to the other:  So I could do 
something like this silly example:

(define add-index-and-constant
   (lambda (el i a)
     (+ el i a)))

(foreach with-vars add-index-and-constant '(1 2 3 4) '(10))
--> (10 13 15 17)

   The current code I've got is below.  I have a couple of inprovements 
I'd like to make though.  The first is I'd like to have a more 
intuitive 'with-vars' mechanism, so I could say

(foreach add-index-and-counter '(1 2 3 4) (with-vars '(10)) [more 
scheme-like IMO]

or perhaps even

(with-vars '(10))
(foreach add-index-and-counter '(1 2 3 4)) [more C-like IMO]

I know that the first at least can be done fairly easily, because 
'cond' does it with the 'else' clause; but it would require that the 
'with-vars' branch of the syntax-rules would need to influence 
something with already happened in the foreach branch (the variables to 
be passed into the function).  I would suppose the second possibility, 
or perhaps the variant

(with-vars '(10)
   (foreach add-index-and-counter '(1 2 3 4)))

could be done if a 'with-vars' syntax rule defined the syntax rule 
'foreach *inside* it, but that seems like a major kludge

   The second thing I'd like to do is to generalize the syntax to any 
number of lists, like map.  The key transformation would be to turn (_ 
func lst1 lst2 ..) into the code in the expansion (func (list-ref lst1 
x) (list-ref lst2 x) .. x)  This is easy for a defined number of lists, 
but how do you do it for the general case?  The define-syntax 
construction as I understand it (not very well ;-) requires that all 
elliptical parameters stay together in the expansion (unless they're 
part of a list, where the list components can be split apart, like (x 
v) .. , but I don't see how that could apply here.

   I've got R. Dybvig's Scheme Programming Language reference, so if 
anyone would like to point out an example in it, that would be great.

Jim Witte

;; code follows
; foreach syntax:
;  take a procedure of form
;  lambda p (el[0] .. el[n] x)
;  and 1 or 2 lists
; pass each element of lst[0]..lst[n] to p, with each element in <el> 
; 0-based index in <x>
; usage:
;  foreach q '(1 2 3 4)
;   with q = (lambda el x)
; foreach with-vars syntax:
;  take a procedure of form
;  lambda p (el[0] .. el[n] x var[0] .. var[m])
;  and 1 or 2 lists, plus an addition list of variables var[0] .. var[m]
; execute like foreach, only pass in var[0] .. var[m] to lambda
; usage:
;  foreach with-vars q '(1 2 3 4) '(10 20 30)
;   with q = (lambda el x a b c)

(define-syntax foreach
   (syntax-rules (with-vars)
     ((_ func lst)
      (let ((len (length lst)))
        (let executor ((x 0))
          (cond ((= x len) '())
                (else (cons (func (list-ref lst x) x)
                            (executor (+ x 1))))))))

     ((_ with-vars func lst lstvars )
      (let ((len (length lst)))
        (let executor ((x 0))
          (cond ((= x len) '())
                (else (cons (apply func (list-ref lst x) x lstvars)
                            (executor (+ x 1))))))))

     ; how do I generalize it to (_ func lst lst1 ...) ?

Posted on the users mailing list.