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

From: John Clements (clements at brinckerhoff.org)
Date: Wed Oct 30 08:39:51 EST 2002

On Tuesday, October 29, 2002, at 09:49  PM, Jim Witte wrote:

>  For list-related administrative tasks:
>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
>>> 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 first element of this should be eleven, right?



If I understand you correctly, you don't need a macro at all.

First, your "with-vars" construct is subsumed by lambda.  That is, if I 
want to take your 'add-index-and-constant' and produce a function like 
it that always gets 10 as its third argument, I can just write (lambda 
(el i) (add-index-and-constant el i 10)).  If you want to generalize 
this, you can write a 'with-vars' function that takes a closure and a 
list of arguments, and produces a closure which appends those arguments 
to the ones passed in.  The code is clearer than the english here:

(define with-vars
   (lambda (fn static-arg-list)
     (lambda args
       (apply fn (append args static-arg-list)))))

As for the index argument, you can add this in a similar way, just by 
writing a function.  I'm calling it indexed-map rather than 
indexed-for-each because (unlike a for-each) it returns the list of 
results:

(define indexed-for-each
   (lambda args
     (when (< (length args) 2)
       (error 'indexed-for-each "indexed for-each requires at least two 
arguments. Given: ~v" (length args)))
     (apply map (append args (list (build-list (length (cadr 
args))(lambda (x) x)))))))

; Does it work?:

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

(indexed-for-each (with-vars add-index-and-constant '(10)) '(1 2 3 4))

=> (11 13 15 17)

Voila!  and you get the multiple-args stuff for free.

In many languages, this might require a macro, because of the variable 
numbers of arguments.  This is a nice example of Scheme's strength; you 
don't need to dip into the macro layer to solve this problem.

Hope this helps,

john clements



Posted on the users mailing list.