Hello Everyone!

I've been experimenting with the idea of performing compile-time
partial evaluation of calls where possible, using a macro.  I must
preface this discussion that I realize it is a bit of an abuse of
macros.  The reasons for this abuse are 1) an attempt to mimic
performance improvements created by C++ template metaprogramming, 2)
to gain a more comprehensive understanding of CLojure, and 3) to
create an example of a "two-level" language that has the same written
form for both levels (compile time and run time).  A lisp, which
provides the opportunity to run code during the compilation phase,
seems like the perfect place to introduce partial evaluation.  Please
feel free to inform me of previous attempts, gotcha's and the like.
With that all out of the way, on to the problem:

Suppose I write a piece of code that has need for the 30th Fibb.
number and we pretend that the FIbb function really has to be naive
and recursive and slow:
(defn fibb [n] (if (< n 2) n (+ (fibb (- n 1)) (fibb (- n 2)))))
(defn my-func [x] (println "X + Fibb(30) is " (+ x (fibb 30))))

Now, you and I know there's no mutation funny-business going on here,
and there's no dependency on any unknowns to calculate (fibb 30), but
as you can see performing this experiment, Clojure and most other
languages will leave (fibb 30) to be evaluated each time.  And it
should, because there /could/ be side-effects or I might want it to
take a long time.

What I would like is to define a macro which will evaluate (fibb 30)
at compile time and then drop in the result:
(defmacro par-eval [form] (eval form))
"But wait!" you say.  That's poor form and besides, it's already
defined as clojure.contrib.macros/const!  Well, I want more than just
evaluating a constant.  I want to write my code as though it were all
meant to be run at run-time, then wrap the code in my par-eval macro
and have it automatically perform all the calculations that can be
performed during compilation.

Sort of a mix between c.c.macros/const and the c.c.template, probably
using techniques from and c.c.macro-utils.  I see two approaches,
which seem to run into the same problem: 1) I can try to eval my form
from the top and if I get an exception, I can try to eval the elements
of form (if it is a seq), or 2) I can go to the leaves of form and try
to eval them and percolate up either the result of evaluation, or the
raw form if evaluation failed.

-- For now, I am ignoring ns issues that might come into play --

Either approach appears to work for functions and produce a
simplified, partially evaluated tree which is then dropped in place of
the macro.  Macros and special forms though cause some issues: 1) you
must avoid processing their arguments blindly since they may represent
something other than normal Clojure code and 2) you must perform
variable substitution when entering a function or let or loop...

To get symbol macros, it looks like Konrad Hinson had to resort to a
reimplementation of the macro-expansion code and Stuart Sierra had to
deal specially with all the different special forms as well in the
template macros.  It looks to me like I might be forced to perform my
own special handling of special forms like 'if and 'let so that I can
perform the correct analysis.  As for macros, I think a call to eval
should expand them for me, as would using macroexpand.

Unlike const, this macro should not fail when eval does, it should
just return the form unmolested.  I haven't come to any strong
conclusions about what to do about lexical variables referred to
within the macro, but really I don't think there is anything that /
can/ be done with them.  If the code has side effects, then some may
be performed during compilation and others may be left for run-time.
You should only use the macro on purely functional expressions.

Any ideas, comments, critiques would be appreciated!
-- Tim

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to