[racket] help: how to make eval see local bindings?

From: Matthias Felleisen (matthias at ccs.neu.edu)
Date: Mon Jul 11 14:15:54 EDT 2011

Now I don't understand at all why you want to use eval in the macro. 
If the right-hand side just returned the lambda that you have there, 
it would automatically capture the variables in the context of the 
gama rule. 

Have you tried just returning the lambda as is from the macro? 


On Jul 11, 2011, at 12:27 PM, maurizio.giorda wrote:

> Ok, I will give you more details about my project... maybe you could be interested
> in it :>
> But first I need to underline that the macro *cannot foresee* which extern variables the
> lambda can reference ... so I cannot adopt your solution:
> (define-syntax mym  
>   (syntax-rules ()
>     [(_ input ...)
>      (let* ([x 10])    ; at this time, I don't know if lambda will use "x", if "x" is bounded   
>                        ; and (if bounded) which is the binding
>  (lambda (stuff)
>          input ...        ;; line 2 
>          x))]))
> 
> Now let's describe my project.
> I have defined a new language in racket, named chemical language (HOCL).
> The basic data structure of HOCL is the "multiset". It is a similar to a vector,
> with the difference that the elements are not ordered, but they move stochastically
> inside the vector (but this is all folks!). The multiset is a sort of chemical container
> (solution) of molecules.
> 
> molecules can be any racket object: numbers?, strings, lists, and "gamma-rules".
> A "gamma-rule" is very similar to a scheme lambda. It is a function
> that captures some elements (chemical molecules) of the multiset and produces
> new molecules. In the chemical language, gamma-rules are the "chemical rules"
> that fire reactions in the mutliset (the chemical solution), and that transform molecules in
> new molecules.
> 
> I implemented a reader for the multiset notation: < molecule1, molecule2, ... >
> where commas separates the multiset elements, and "<" ">" are  multiset delimiters.
> 
> I create and bind a multiset in this way 
> 
> (define m < 1,2,3,4,(replace x y by (+ x y)), 5, 6 >)  ; top level definition
> < 1,2,3,4, #<procedure>, 5, 6 >                           
> ; the output is a chemical container with a gamma-rule inside it (plus other molecules)
> ; the "x" and "y" free variables of the rule are bound to molecules by a pattern matching
> mechanism, 
> 
> Now I have a chemical engine ("cham") that starts reactions in the chemical solution.
> The gamma-rules are applied to the mutliset (with the sheme "apply").
> > (cham m)
> < 21, #<procedure> >
> 
> As you see the chemical rule (gamma-rule) applies many times, and each time it adds 
> pairs of molecules until one molecule (the total sum) is left (the chemical inert state). 
> 
> Now let's talk about the "gamma-rule" generation: the macro "replace ... by ... "
> generate the gamma-rule code 
> (define-syntax replace
>  (syntax-rules (replace)
>    [(replace input ...)
>     (let* (...)
>       (eval `(lambda (cntx)  ; the code of the "gamma-rule"
>                 ...      
>              ))]))
> 
> 
> Now the problem... In the previous example I can define a rule like this:
> 
> (replace x y by (+ x y) if (> top (+ x y))), 5, 6 >)
> 
> that is, I want the reaction to take place only if the partial sum of molecules is not over "top",
> where the "top" variable may be externally defined.
> Now I can write the code:
> 
> (let ((top 8)
>        (m < 1,2,3,4,(replace x y by (+ x y) if (> top (+ x y))), 5, 6 >)))   ; multiset elements are evaluated after reading
>   (cham m))
> reference to undefined identifier: top
> 
> ... I hope now it is clear that I need to generate procedures with references to symbols that can
> (or cannot) have bindings when the procedure is called... in fact, the user writes 
> the (replace ....) form but the system cannot foresee which extern symbols the generated procedure
> may use.
> 
> Thank you for your attention.
> Sorry for a so long email... I couldn't explain my probelm with less details.
> Maurizio.
> 
> Il 11/07/2011 17.26, Matthias Felleisen ha scritto:
>> 
>> This sounds a bit confused. Allow me to tease out a clarification. 
>> 
>> 1. If you write a macro like this: 
>> 
>> (define-syntax mym 
>>   (syntax-rules ()
>>     [(_ input ...)
>>      (let* ([x 10])
>>        (lambda (stuff)
>>          input ...        ;; line 2 
>>          x))]))
>> 
>> 'hygiene' gives you a couple of different things: 
>> 
>> -- the x and the stuff introduced in the macro doesn't accidentally interfere with free variables in input ... on line 2
>> 
>> -- the let* and the lambda are guaranteed to refer to the meaning in place where you define the macro 
>> 
>> 
>> 2. So when you run this expression in the context of mym 
>> 
>> (let ([x 42])           ;; line 9
>>   ((mym (displayln x))  ;; line 7
>>    'random-argumnent))
>> 
>> you see 
>> 
>> -- the output 42 from the displayln on line 7 
>> -- the result 10 from the line below line 2 
>> 
>> 
>> 3. It is rare that mym needs to generate code involving the x on line 9 WITHOUT specifying the x in an input position for mym. 
>> 
>> QUESTION: can you explain why you'd want to do so? 
>> POSSIBLE ANSWER: you may wish to break hygiene then. 
>> 
>> 4. It is equally rare that you want let* or lambda to mean what the context of the macro call says they are. 
>> 
>> IF THIS IS WHAT YOU WANT, can you provide more details. 
>> 
>> 
>> 
>> 
>> 
>> 
>> 
>> On Jul 11, 2011, at 11:04 AM, Maurizio Giordano GMAIL wrote:
>> 
>> 
>>> On Mon, 2011-07-11 at 13:43 +0100, Noel Welsh wrote:
>>> 
>>>> On Mon, Jul 11, 2011 at 1:26 PM, Maurizio Giordano GMAIL
>>>> 
>>>> <maurizio.giorda at gmail.com>
>>>>  wrote:
>>>> 
>>>>> PS. my lambda is generated by a macro (define-syntax) ...
>>>>> this is why I use eval to generate the corresponding procedure.
>>>>> 
>>>> If this is the case I don't think you need to use eval. You either
>>>> need to write your macro in a hygenic way -- it accepts as parameters
>>>> all the identifiers in the enclosing environment that is should
>>>> reference -- or you should explicitly break hygiene. If you're new-ish
>>>> to Racket the preceeding sentence probably won't make any sense, so
>>>> feel free to ask for more help!
>>>> 
>>>> Cheers,
>>>> N.
>>>> 
>>> Hi Nole,
>>> Yes, I am an absolute new-ish to racket... I would like to know more
>>> about writing a macro by "explicitly break hygiene". 
>>> I supposed I didn't need to use eval... but for me it is 
>>> the easiest way to "build" a lambda-code and then evaluate it.
>>> 
>>> I want to give you more details about my problem.
>>> I have a macro like this:
>>> 
>>> (define-syntax mymacro
>>>  (syntax-rules (mymacro)
>>>    [(mymacro input ...)
>>>     (let* (...)
>>>       (eval `(lambda (cntx) 
>>>                 ...      ; a code generated according to macro
>>> "input ..."
>>>                 (+ x 2)  ; that contains references to an outside "x"
>>> symbol
>>>                 ...
>>>              ))]))
>>> 
>>> Note that I cannot foresee which extern symbols are referenced by the 
>>> generated lambda.
>>> This macro returns a procedure.
>>> if I use my macro in a "let" construct, of course I have a "reference to
>>> an undefined identifier":  
>>> 
>>> (let* ((x 1) 
>>>       (f (mymacro ...)))
>>>     (f 2))
>>> reference to undefined identifier: x
>>> 
>>> So, coming back to my question: since the eval is called within the
>>> "let"
>>> scope, is it possible to make it aware of the bindings of the "let"? 
>>> Do you know alternative mechanism to do that?
>>> 
>>> TIA,
>>> Cheers,
>>> 
>>> Maurizio.
>>> 
>>> _________________________________________________
>>>  For list-related administrative tasks:
>>>  
>>> http://lists.racket-lang.org/listinfo/users
> 
> 
> -- 
> <btn_viewmy_160x25.png>




Posted on the users mailing list.