On Oct 1, 2005, at 7:37 PM, Eric Mahurin wrote:



> --- Bob Hutchison <hutch / recursive.ca> wrote:
>
>
>
>> On Oct 1, 2005, at 4:55 PM, Eric Mahurin wrote:
>>
>>
>>
>>> Here's one - a poor man's macro facility.  Let's say a
>>>
>>>
>>>
>> macro is
>>
>>
>>
>>> just a lambda that returns a string.  You just eval it when
>>>
>>>
>>>
>> you
>>
>>
>>
>>> need to execute the code for that macro.
>>>
>>> plus  = lambda { |a,b| "(#{a}+#{b})" }
>>> # will have to re-evaluate a or b if they are an expression
>>> min1  = lambda { |a,b| "(#{a}<#{b} ? #{a} : #{b})" }
>>> # use local variables to prevent re-evaluation
>>> min2  = lambda { |a,b| "(a=#{a};b=#{b};a<b ? a : b)" }
>>>
>>> # y+z may get evaluated twice
>>> min1["x",plus["y","z"]]
>>> # => "(x<(y+z) ? x : (y+z))"
>>>
>>> # y+z may evaluated once
>>> min2["x",plus["y","z"]]
>>> # => "(a=x;b=(y+z);a<b ? a : b)"
>>>
>>> # need to localize a/b for the inner min2
>>> min2["x",min2["y","z"]]
>>> # => "(a=x;b=(a=y;b=z;a<b ? a : b);a<b ? a : b)"
>>>
>>>
>>> See the problem on this last example?  We really need to
>>> localize a and b.  There isn't a good facility to do this.
>>>
>>>
>>>
>>>
>>>
>>
>> You need gensym as lisp has (and I had in a previous
>> example), in
>> which case you get this back on the last example, and there
>> is no
>> problem:
>>
>> (a_1=x;b_2=(a_3=y;b_4=z;a_3<b_4 ? a_3 : b_4);a_1<b_2 ? a_1 :
>> b_2)
>>
>>
>>
>
> Yes, something like this would work (using your Gensym module):
>
> min2  = lambda { |a,b|
>   v1 = Gensym.gensym
>   v2 = Gensym.gensym
>   "(#{v1}=#{a};#{v2}=#{b};#{v1}<#{v2} ? #{v1} : #{v2})"
> }
>
> Here are the disadvantages of this compared to having ruby do
> local variables:
>
> - not as natural/uglier
>
>

No argument there at all, I agree. However a little syntactic sugar  
would make all the difference. I made a suggestion off the top of my  
head as to what that might look like, but I've got no doubt that that  
can be improved.

You might be able to make an argument that local variables are more  
fundamental and that a macro system shouldn't be the way to solve the  
problem. Though, the problem that motivated this discussion, which I  
believe amounted to a problem with in-lining functions, is probably  
better solved by the macro system.



> - clutters the namespace/variable table
>
>

Actually it doesn't in the current ruby. In the example I gave  
earlier the gensymed names are not visible outside the eval.



> - prevents GC from freeing objects that these variables
> reference
>
>
>

Not if they don't exist (as I think they don't)


And the advantage is that you'd have a macro system

Cheers,
Bob

----
Bob Hutchison          -- blogs at <http://www.recursive.ca/hutch/>
Recursive Design Inc.  -- <http://www.recursive.ca/>
Raconteur              -- <http://www.raconteur.info/>