<div dir="ltr">On Thu, Jul 11, 2013 at 1:49 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>Thank you. You answer is very useful.<div class="im"><br><br>> You have to be careful about duplicating inputs in expanded code.<br><br></div>I thought, that hygiene implies not only cl:gensym, but also once-only. Is there something like <a href="http://common-lisp.net/project/cl-utilities/doc/once-only.html" target="_blank">http://common-lisp.net/project/cl-utilities/doc/once-only.html</a> in Racket?</div>
</blockquote><div><br></div><div>Hygiene is about the scope of names, and has nothing to do with duplicate expressions. Neither does once-only. What once-only means, is that the contained, single expression is not called multiple times at run-time. What your macro did is not to evaluate a single expression twice, but instead to construct _two_ separate expressions. Each was still only executed once. Hygiene makes no guarantee about copying expressions; however, hygiene does give macro implementers better tools for _avoiding_ copying, because it's easier and safer to bind values to so-called "temporary" variables without unintended scope violation.<br>
<br></div><div>In a case where you do have one expression, and want it to be executed once, the macro called `begin-lifted` from the module mzlib/etc is the equivalent of once-only. But that's not the issue in your square macro.<br>
</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div class="im">> A lot of the benefits you get from explicit optimization will also come from using define-inline from racket/performance-hint.<br>
<br></div>Do you think, that Racket will do pure calculations in compile-time?<br><br>For example, if I write<br><br>(+ x (* 2 3 4) (sin 20))<br><br>will it be optimized to <br><br>(+ x 24.912945250727628) ?<br><br>Or I have to use define-syntax to do it?<br>
</div></blockquote><div><br></div><div>Racket will do many pure calculations at compile-time, without any work on your part. I don't know exactly what it will and won't do. I know the Typed Racket optimization coach will help you make use of the extra optimizations that Typed Racket performs, but I don't know what it tells you about the core Racket optimizer.<br>
<br></div><div>In general, I suggest writing your code in the most natural style first. If you find that it runs too slow, then start thinking about where you could add manual optimizations. It will almost certainly not be with a function for squaring numbers. Our optimizer handles that kind of thing quite well already, and even before it did, that kind of function is not a serious bottleneck anyway. Save the effort of optimization until you know where it will do the most good.<br>
<br></div><div>--Carl<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div>Четверг, 11 июля 2013, 0:26 -04:00 от Carl Eastlund <<a href="mailto:cce@ccs.neu.edu" target="_blank">cce@ccs.neu.edu</a>>:<div>
<div class="h5"><br>
<blockquote style="border-left:1px solid #0857a6;margin:10px;padding:0 0 0 10px">
        <div>
        
        
        
        
        
        
        
        
<div>
        
        <div>
                
                
                        <div><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="https://e.mail.ru/sentmsg?mailto=mailto%3akalimehtar@mail.ru" target="_blank">kalimehtar@mail.ru</a>></span> wrote:<br>
<div>
<div><blockquote 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><font color="#888888"><br><br>-- <br>Roman Klochkov</font></span></div></blockquote></div></div></div></div></div></div>
</div></div></div></div></div></div></div></div></div></div></blockquote></div></div></div></blockquote></div></div></div>