[racket] Macro + function automation
Roman,
Bear in mind that by expanding (square x) to (square x x), that means if
someone writes
(square (perform-expensive-computation))
then you will expand it to:
(* (perform-expensive-computation) (perform-expensive-computation))
You have to be careful about duplicating inputs in expanded code.
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.
If you still prefer to manually expand these things, then I suggest
something like the following:
(require (for-syntax syntax/parse))
(define-syntax (square stx)
(define/syntax-parse body #'(* x x))
(syntax-parse stx
#:literals [square expt]
[(square (square e:expr)) #'(expt e 4)]
[(square (expt e:expr n:number))
(define/syntax-parse 2n (* 2 (syntax-e #'n)))
#'(expt e '2n)]
[(square (expt e:expr n:expr)) #'(expt e (* n 2))]
[(square e:expr) #'(let ([x e]) body)]
[square #'(lambda (x) body)]))
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.
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.
On Thu, Jul 11, 2013 at 12:09 AM, Roman Klochkov <kalimehtar at mail.ru> wrote:
> I like to make syntax-optimized functions.
>
> (define-syntax (square stx)
> (syntax-case stx (square expt)
> [(square (square expr)) #'(expt expr 4)]
> [(square (expt expr n)) (if (number? (syntax-e #'n))
> #`(expt expr #,(*
> (syntax-e #'n) 2))
> #'(expt expr (* n 2)))]
> [(square x) #'(* x x)]
> [square #'(lambda (x) (* x x))]))
>
> 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.
>
> But I dislike to repeate the body of the function in last two cases.
>
> I tryed
>
> (define-syntax (square stx)
> (let ([body #'(* x x)])
> (syntax-case stx (square expt)
> ...
> ...
> [(square x) body]
> [square #'(lambda (x) #`body)]))
>
> but hygiene prevents me from that: x: unbound identifier in module in: x
> How can I bind template body with some variable? Or how to rewrite the
> syntax to evade duplication?
>
> --
> Roman Klochkov
>
> ____________________
> Racket Users list:
> http://lists.racket-lang.org/users
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20130711/a0afacac/attachment.html>