This looks really nice; good work!

To force evaluation of lazy constructs, you can use 'doall' and 'dorun'. 
Can you show the snippet with this problem?

Sanel

On Thursday, April 5, 2012 1:19:32 AM UTC+2, Andru Gheorghiu wrote:
>
> Sorry for dropping off the radar, I was caught up in some homework for 
> college. 
> I've written a very simple program for a limited form of constant 
> folding: 
>
> ; Forces evaluation of an expression or returns the expression if 
> ; it can be evaluated 
> (defn force-eval [exprs] 
>   (try (eval exprs) 
>     (catch Exception e exprs))) 
>
> ; Recursively evaluates expressions and subexpressions achieving 
> ; constant folding 
> (defn eval-deep [exprs] 
>   (if (not (list? exprs)) 
>       exprs 
>       (let [evaled (force-eval exprs)] 
>         (if (list? evaled) 
>             (map eval-deep evaled) 
>             evaled)))) 
>
> ; Checks if the given argument is a boolean type 
> (defn boolean? [x] 
>   (or (true? x) (false? x))) 
>
> ; Replaces an if for which the test condition is known with the 
> ; corresponding branch (then for true, else for false) 
> (defn replace-if [exprs] 
>   (cond (or (not (list? exprs)) (empty? exprs)) exprs 
>         (= (first exprs) 'if) 
>           (if (boolean? (nth exprs 1)) 
>             (if (nth exprs 1) 
>               (first (replace-if (drop 2 exprs))) 
>               (first (replace-if (drop 3 exprs)))) 
>           (map replace-if exprs)) 
>         :else (map replace-if exprs))) 
>
> ; Combines eval-deep and replace-if 
> (defn optimize [exprs] 
>   (let [reduced (reverse (into nil (eval-deep exprs)))] 
>     (replace-if reduced))) 
>
> The basic idea was to use exception handlers to try to evaluate and 
> expression if it can be evaluated and if so, replace it with it's 
> evaluated form. Then recursively apply this function to an expression 
> and, if necessary, all subexpressions. 
> I've also added a function to reduce if statements. Similar functions 
> can be written for cond, condp, case. 
>
> I did have a problem: for some reason my eval-deep function returns a 
> lazy sequence for the expressions that can't be evaluated. This was an 
> inconvenient when I was trying to apply another function (namely 
> replace-if) on the result of eval-deep. To get around this I converted 
> the lazy sequence into a persistent list, but this lead to that ugly 
> application of functions in the let in optimize. How could I have 
> avoided this? 
>
> Andru Gheorghiu 
>
> On Mar 22, 1:41 pm, Andru Gheorghiu <androi...@gmail.com> wrote: 
> > Thank you for the responses. I'm looking into the resources you gave 
> > me. 
> > 
> > Andru Gheorghiu 
> > 
> > On Mar 21, 1:16 pm, Sanel Zukan <san...@gmail.com> wrote: 
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > >  I'm happy to see you are familiar with the subject :) 
> > 
> > > I was thinking that a 
> > 
> > > > similar program forClojurecould detect stack recursive functions and 
> > > > replace them with their iterative counterparts, though this can be 
> > > > somewhat difficult as various loop-holes can arise that would "fool" 
> > > > the program. 
> > 
> > > This isn't a big issue, as recursive functions aren't much advised in 
> > >Clojure. However, ideal solution would be to detect tail calls and 
> rewrite 
> > > block in loop/recur combo. This would allowClojureto fully reuse TCO 
> > > without waiting for JVM to implement it (which will probably never 
> happen). 
> > 
> > > I suppose an approach can be found which makes the best out of both 
> > 
> > > > worlds: a tree shaker and constant folding implementation + an 
> > > > automated program which detects recursions and replaces them with 
> more 
> > > > efficient versions and a rule-based system to cover some cases which 
> > > > the first approach misses. 
> > 
> > > Using all this tasks would impose a bit of work to complete them all. 
> I 
> > > would advise taking smaller steps in form of real tasks, followed with 
> > > rigorous tests. It can look like this: 
> > 
> > >  * constant folding 
> > >  * empty let removal 
> > >  * lambda reduction 
> > >  * TCO 
> > >  * simplification (using Kibit or directly core.logic) 
> > >  * ... 
> > 
> > > If you decide to work on this, for the starting point you can look at 
> > > "optimizer.scm" (from CHICKEN source) which is nicely summarized at 
> [1] and 
> > > Egi'scode[2]. Both of them applies common techniques in quite readable 
> > > manner. Of course, if someone else have additional resource, please 
> share 
> > > it :) 
> > 
> > > Sanel 
> > 
> > > [1]
> http://wiki.call-cc.org/chicken-internal-structure#the-optimizer-opti... 
> > > [2]https://bitbucket.org/egi/compiler/src 
> > 
> > > On Tuesday, March 20, 2012 7:30:41 PM UTC+1, Andru Gheorghiu wrote: 
> > 
> > > > Thank you for the clarifications and the resources, I understand now 
> > > > what tree shaking is. In fact, I had a project last year at our 
> > > > college to implement (in Scheme) a constant foldingoptimizerfor 
> > > > Scheme programs, I now see the resemblance with what you described. 
> > > > The program would optimize functions like: 
> > 
> > > > (define some-function 
> > > >     (lambda (x) 
> > > >          (if (> x (+ 2 4)) 
> > > >             (- 7 (car ‘(1 2 3))) 
> > > >             (cons x 4))) 
> > 
> > > > Turning it into 
> > 
> > > > (define some-function 
> > > >     (lambda (x) 
> > > >        (if (> x 6) 
> > > >            6 
> > > >            (cons x 4)))) 
> > 
> > > > Also, when finding conditional statements in which the test 
> condition 
> > > > is known (can be evaluated) to replace it with thecodewhich runs on 
> > > > the appropriate branch. For example, replacing: 
> > 
> > > > (if (or #f #t) 
> > > >     then-code 
> > > >     else-code) 
> > 
> > > > With 
> > 
> > > > then-code 
> > 
> > > > Same thing for cond. 
> > 
> > > > Another part of the project was to classify recursive functions into 
> > > > stack recursive, tree recursive or iterations. I was thinking that a 
> > > > similar program forClojurecould detect stack recursive functions and 
> > > > replace them with their iterative counterparts, though this can be 
> > > > somewhat difficult as various loop-holes can arise that would "fool" 
> > > > the program. 
> > > > I suppose an approach can be found which makes the best out of both 
> > > > worlds: a tree shaker and constant folding implementation + an 
> > > > automated program which detects recursions and replaces them with 
> more 
> > > > efficient versions and a rule-based system to cover some cases which 
> > > > the first approach misses. 
> > 
> > > > Andru Gheorghiu 
> > 
> > > > On Mar 20, 1:31 am, Sanel Zukan <san...@gmail.com> wrote: 
> > > > > Hi Andru and thank you for expressing interest in this proposal. 
> > 
> > > > > > Could you please give more details (or examples) on the types of 
> > > > > > optimizations theoptimizershould be able to do? Also, what is a 
> tree 
> > > > > > shaker implementation? 
> > 
> > > > > As David wrote, this is deadcodeelimination and in LISP world is 
> also 
> > > > > known as tree shaking. Contrary to pattern matching (for which you 
> > > > > expressed desire), deadcodeelimination is usually more advanced 
> > > > approach, 
> > > > > sometimes requiring passing through thecodemultiple times, 
> inspecting 
> > > > > compiler facilities or simply doing a bunch of tricks to remove 
> obvious 
> > > > and 
> > > > > not so obvious unusedcode. 
> > 
> > > > > Take this example: 
> > 
> > > > >   (defonce *always-true* true) 
> > > > >   (if *always-true* 
> > > > >      (println "Always executed") 
> > > > >      (println "Never executed")) 
> > 
> > > > > Matching this case could be hard for pattern matching tools; they 
> often 
> > > > do 
> > > > > not understand the content outside given pattern. 
> Trueoptimizerwould 
> > > > pick 
> > > > > up *always-true* and notice it will never be changed for this 
> block. 
> > > > > However, if I do some weird magic inside some function and 
> globally 
> > > > change 
> > > > > the value of *always-true* at some point,optimizershould recognize 
> > > > this 
> > > > > case or would remove validcode. 
> > 
> > > > > Also, often case for optimizers is to precompute simple 
> expressions in 
> > > > > compilation phase yielding static values, like: 
> > 
> > > > >   (let [a 0 
> > > > >          b (+ a 1)] 
> > > > >     (if something 
> > > > >       b)) 
> > 
> > > > > here it could rewrite whole block as: 
> > 
> > > > >  (if something 
> > > > >    1) 
> > 
> > > > > or even can recognizeClojurepatterns like: 
> > 
> > > > >  (apply + (range 1 10)) 
> > 
> > > > > where the pattern matching approach could rewrite expression to (+ 
> 1 2 3 
> > > > 4 
> > > > > 5 6 ... 9) andoptimizerwould simply produce 45. Using this case 
> you 
> > > > can 
> > > > > see how pattern matching can be a part ofoptimizer. 
> > 
> > > > > I'm hoping I manage to fully describe you an idea behind this 
> proposal. 
> > > > Of 
> > > > > course, taking some expert system approach and doing Kibit-style 
> > > > matching 
> > > > > can be a good starting point too :) 
> > 
> > > > > Also, if you are interested to take tree shaking way, a good 
> starting 
> > > > point 
> > > > > can be SBCL alpha shaker athttp://jsnell.iki.fi/tmp/shake.lisp. 
> > > > > Unfortunately without documentation, but thecodeis quite easy to 
> > > > follow. 
> > 
> > > > > Sanel 
> > 
> > > > > On Saturday, March 17, 2012 10:59:44 PM UTC+1, Andru Gheorghiu 
> wrote: 
> > 
> > > > > > Hello, 
> > 
> > > > > > I am a third year student majoring in computer science and I am 
> > > > > > interested in theClojurecodeoptimizerproject proposed for GSoC 
> > > > > > 2012. Could you please give more details (or examples) on the 
> types of 
> > > > > > optimizations theoptimizershould be able to do? Also, what is a 
> tree 
> > > > > > shaker implementation? 
> > > > > > I was thinking that anoptimizercould be implemented as a rule 
> engine 
> > > > > > similar to Jess or CLIPS in which rules contains patterns which 
> need 
> > > > > > to be replaced and thecodeto replace them with. For example one 
> > > > > > could write patterns for generic linear recursive functions that 
> > > > > > should be replaced with linear iterative functions. Similarly 
> patterns 
> > > > > > can be written for functions which replicate the behavior of an 
> > > > > > already existing function (such as reverse, map, apply etc) and 
> a rule 
> > > > > > to replace those functions with the predefined ones. 
> > 
> > > > > > Thank you, 
> > > > > > Andru Gheorghiu

-- 
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