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
