<div dir="ltr"><div><div><div><div><div><div>Roman,<br><br></div>Bear in mind that by expanding (square x) to (square x x), that means if someone writes<br><br> (square (perform-expensive-computation))<br><br></div>then you will expand it to:<br>
<br></div> (* (perform-expensive-computation) (perform-expensive-computation))<br><br></div><div>You have to be careful about duplicating inputs in expanded code.<br></div><div><br></div>A lot of the optimizations you are performing manually will be done by the Racket optimizer anyway; more if you use Typed Racket with optimizations on, and you can always use the Optimization Coach to find more. A lot of the benefits you get from explicit optimization will also come from using define-inline from racket/performance-hint.<br>
<br>If you still prefer to manually expand these things, then I suggest something like the following:<br><br>(require (for-syntax syntax/parse))<br><br>(define-syntax (square stx)<br> (define/syntax-parse body #'(* x x))<br>
(syntax-parse stx<br> #:literals [square expt]<br> [(square (square e:expr)) #'(expt e 4)]<br> [(square (expt e:expr n:number))<br> (define/syntax-parse 2n (* 2 (syntax-e #'n)))<br> #'(expt e '2n)]<br>
[(square (expt e:expr n:expr)) #'(expt e (* n 2))]<br> [(square e:expr) #'(let ([x e]) body)]<br> [square #'(lambda (x) body)]))<br><br></div>Note that syntax-parse lets you check for numeric inputs in the pattern, and define/syntax-parse lets you bind pattern variables. There isn't a problem with "x" here, because the name is not used as a pattern variable, it's a variable name introduced by the macro everywhere it occurs.<br>
<br></div>If you're unfamiliar with syntax-parse, I encourage you to learn it, but you can always use syntax-case and replace define/syntax-parse with define/with-syntax from the racket/syntax module.<br><div><div><div>
<div><div><div><div><div><div><br>On Thu, Jul 11, 2013 at 12:09 AM, Roman Klochkov <span dir="ltr"><<a href="mailto:kalimehtar@mail.ru" target="_blank">kalimehtar@mail.ru</a>></span> wrote:<br><div class="gmail_extra">
<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div><p>I like to make syntax-optimized functions.<br><br>(define-syntax (square stx)<br> (syntax-case stx (square expt)<br> [(square (square expr)) #'(expt expr 4)]<br> [(square (expt expr n)) (if (number? (syntax-e #'n))<br>
#`(expt expr #,(* (syntax-e #'n) 2))<br> #'(expt expr (* n 2)))]<br> [(square x) #'(* x x)]<br> [square #'(lambda (x) (* x x))]))<br>
<br>So I can write (square (expt x 5)) and have evaluate (expt x 10) and I can write (map square '(1 2 3)) and it is also works.<br><br>But I dislike to repeate the body of the function in last two cases.<br><br>I tryed <br>
<br></p><p>(define-syntax (square stx)<br> (let ([body #'(* x x)])<br> (syntax-case stx (square expt)<br> ...<br> ...<br> [(square x) body]<br> [square #'(lambda (x) #`body)]))<br><br>but hygiene prevents me from that: x: unbound identifier in module in: x</p>
How can I bind template body with some variable? Or how to rewrite the syntax to evade duplication?<span class=""><font color="#888888"><br><br>-- <br>Roman Klochkov</font></span></div>
<br>____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/users</a><br>
<br></blockquote></div><br></div></div></div></div></div></div></div></div></div></div></div>