guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Function call inside macros


From: Alex Shinn
Subject: Re: Function call inside macros
Date: 02 Sep 2001 11:37:55 -0400
User-agent: Gnus/5.0808 (Gnus v5.8.8) Emacs/21.0.104

>>>>> "Sergey" == Sergey Dolin <address@hidden> writes:

    Sergey> It's time to return to old disscussion about 'memoizing'
    Sergey> macros, isn't it?

Even if you could get this to work with a non-memoizing macro, what
you'd be doing is effectively re-compiling the expression each time.
You're not getting around the fact that dynamic let bindings will
require a run-time compile, typically done with eval.

Perhaps.  It should be possible to compile the body once and eval it
in a dynamic environment which has the right bindings at run-time.
The closest I got was:

(define-macro (http:let binds . body)
  `(let* ((%proc (lambda () ,@body))
          (%local (make-leaf-environment))
          (%imported (make-leaf-environment))
          (%env (make-eval-environment %local %imported)))
     (environment-define %env (quote %proc) %proc)
     (for-each (lambda (x) (environment-define %env (car x) (cdr x)))
               (http:uri-query-string->lists (getenv "QUERY_STRING")))
     (eval (list (quote %proc)) %env)))

But oddly enough you can't pass an environment created with
make-eval-environment to eval!  eval expects a module, but if you pass
it (env-module %env) then that's the top-level module the %env was
created in, which won't have the bindings you just set.  Perhaps
someone who understands the module system better can help here :)

Another approach is to create a procedure which takes the given query
arguments and apply it to the current values.  Although this means
compiling a different procedure for each set of query parameters, you
can store the procs in a lookup table.  In practice, a CGI page
typically gets relatively few variations in the names of CGI
parameters, so the only real overhead here is mapping the query string
to the cached proc.  As a simplified example (leaving out binds), I
got the following to work:

(define %lookup (make-hash-table 31))
(define-macro (http:let . body)
  `(let* ((%query (http:uri-query-string->lists (getenv "QUERY_STRING")))
          (%vars (map car %query))
          (%proc (hash-ref %lookup %vars #f)))
     (cond ((not %proc)
            (set! %proc (eval (cons (quote lambda)
                                    (append (list %vars)
                                            (cons (quote begin)
                                                  (quote (list ,@body)))))
                              (current-module)))
            (hash-set! %lookup %vars %proc)))
     (apply %proc (map cadr %query))))

so you do the expansion every time, but only call eval if you haven't
already compiled the body for that set of parameters.

    Sergey> I want to make guile PHP killer, and want to simulate all
    Sergey> fetures of it.

Write a PHP translator :) Seriously, even if you consider PHP syntax
ugly, Scheme excels at writing simple languages, and if you write
you're own web scripting language in Scheme you can add whatever kind
of magic you want to it.  And since HTML is structurally similar to
Scheme, you could use the HTML itself as your language and have tags
like <let>.  There's even a good parser already available, SXML.

HTH,

-- 
Alex Shinn <address@hidden>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]