Very good solution :)

To continue this discussion, feel free to mail me; we will also reduce some 
noise here on the list.

Sanel

On Friday, April 6, 2012 6:47:37 PM UTC+2, Andru Gheorghiu wrote:
>
> It's ok now. The problem was in the let of the optimize function... 
> initially I had: 
>   (let [reduced (reverse (into nil (eval-deep exprs)))] 
> because exprs was a lazy sequence and I wanted to turn it into a list. 
> I replaced the "(reverse (into nil ..." part with "(apply list ..." 
> and it works just fine :) 
>
> The problem is that this implementation doesn't account for variable 
> scoping, I need to fix that. 
> For example if I have 
>
> (def n 10) 
> (let [ n 5 ] (+ (+ n 6) something)) 
>
> If i try to optimize the let it will return 
>
> (let [ n 5 ] (+ 16 something)) 
>
> Because it uses the global n defined outside the let. 
>
> Andru Gheorghiu 
>
> On Apr 6, 10:56 am, Sanel Zukan <[email protected]> wrote: 
> > 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 
> > 
> > ... 
> > 
> > read more »

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

Reply via email to