[racket] Macro + function automation

From: Carl Eastlund (cce at ccs.neu.edu)
Date: Thu Jul 11 00:26:53 EDT 2013


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>

Posted on the users mailing list.