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

From: maurizio.giorda (maurizio.giorda at gmail.com)
Date: Mon Jul 11 12:27:57 EDT 2011

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


-- 
View Maurizio Giordano's profile on LinkedIn 
<http://it.linkedin.com/in/giordanomaurizio><http://it.linkedin.com/in/giordanomaurizio>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20110711/fcf371db/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: btn_viewmy_160x25.png
Type: image/png
Size: 1208 bytes
Desc: not available
URL: <http://lists.racket-lang.org/users/archive/attachments/20110711/fcf371db/attachment.png>

Posted on the users mailing list.