From: Jesse Jones Date: 2004-08-04T20:51:32+09:00 Subject: Re: Macros in Ruby In article <41106A47.7050901@weirichhouse.org>, Jim Weirich wrote: > Jesse Jones wrote: > > percent-case > > 0.75 case > > normal_hit > > end > > > > 0.20 case > > critical_hit > > end > > > > otherwise > > kill_foe > > end > > end > > I spent about 10 minutes coding this in Ruby (and it turned out to be > very similar to Joel VanderWerf's version that he posted). Joel's solution was very cool. Certainly a lot better than any non-macro solution I was able to come up with in a dynamic language I was toying with. > I'm curious > what a macro version would be like. What would the implementation of > percent_case look like in Lisp or Dylan macros? Here's a Dylan-ish macro: macro percent-case is statement as body {percent-case ?cases end} => {local n = random() if false 0 ?cases end} cases: {} => {} {otherwise ?:body end} => {else ?body} {?percent:float-literal case ?:body end ...} => {elsif (n -= ?percent) <= 0.0 ?body ...} end In the first line we tell the compiler that we're augmenting the language's statement production and that the macro expansion should be reparsed using the body production. The code in the first set of braces is the pattern for the main-rule (this macro only has one main-rule). ?cases refers to an aux-rule named cases. So, the macro matches code that starts with a 'percent-case' token, followed by something that matches the aux-rule, followed by an 'end' token. The code in braces after the => is what the macro expands to. In this case some simple logic plus whatever the aux rule expands to. The aux rule has three cases which are tried in order. 1) It tries to match nothing, if this succeeds the aux rule expands to nothing. 2) It tries to match the otherwise clause, if this succeeds the aux rule expands to an else clause. 3) It tries to match a floating-point literal followed by 'case', a body production, and 'end'. If we get a match the aux rule expands to an elsif clause. The ... means the aux rule is recursively invoked again so we essentially iterate until we run out of cases. Note that the macro defines an 'n" local variable. Because macros are hygienic any references to n within the body of the macro refer to that n even if the macro call site has a variable named n in scope. -- Jesse