Prev: declaring 'ignore' inside a loop using destructuring
Next: The Best gift for this year christmas day!
From: Don March on 26 Nov 2009 20:46 On Nov 26, 5:32 am, p...(a)informatimago.com (Pascal J. Bourguignon) wrote: > Don March <don.ma...(a)gmail.com> writes: > > A function I'm writing has a section like this: > > > (dolist (x long-list) > > (do-some-stuff) > > (push (if fn > > (funcall fn x) > > x) > > new-list)) > > > Which is fine, but if long-list is actually long, it's silly and > > possibly slow to evaluate the "(if fn..." stuff every time. I came up > > with the following 2.5 alternatives: > > > ;; option 1 (probably implemented with macros to avoid duplicate code) > > (if fn > > (dolist (x long-list) > > (do-some-stuff) > > (push (funcall fn x) new-list)) > > (dolist (x long-list) > > (do-some-stuff) > > (push x new-list))) > > Notice that any compiler worth its bits will do that transformation > automatically (moving constant computations outside of loops), perhaps > with (declaim (optimize (speed 3) (space 1))). > > Otherwise if you have to do it yourself, use a macrolet as indicated > by joswig. > > -- > __Pascal Bourguignon__ After experimenting a bit, it seems SBCL runs both versions at about the same speed. CLISP runs the code with the constant computations moved outside the loop in about 94% of the time as the original code, no matter what optimization settings I try. The code wasn't really a bottleneck, I'm just trying to learn to write lisp in a way that wouldn't make experts cringe. (Apparently the "ugly and slow" eval version would fall in that category :) ) Thanks for your help, everyone.
From: Alberto Riva on 28 Nov 2009 16:37 Don March wrote: > On Nov 26, 5:32 am, p...(a)informatimago.com (Pascal J. Bourguignon) > wrote: >> Don March <don.ma...(a)gmail.com> writes: >>> A function I'm writing has a section like this: >>> (dolist (x long-list) >>> (do-some-stuff) >>> (push (if fn >>> (funcall fn x) >>> x) >>> new-list)) >>> Which is fine, but if long-list is actually long, it's silly and >>> possibly slow to evaluate the "(if fn..." stuff every time. I came up >>> with the following 2.5 alternatives: >>> ;; option 1 (probably implemented with macros to avoid duplicate code) >>> (if fn >>> (dolist (x long-list) >>> (do-some-stuff) >>> (push (funcall fn x) new-list)) >>> (dolist (x long-list) >>> (do-some-stuff) >>> (push x new-list))) >> Notice that any compiler worth its bits will do that transformation >> automatically (moving constant computations outside of loops), perhaps >> with (declaim (optimize (speed 3) (space 1))). >> >> Otherwise if you have to do it yourself, use a macrolet as indicated >> by joswig. >> >> -- >> __Pascal Bourguignon__ > > After experimenting a bit, it seems SBCL runs both versions at about > the same speed. CLISP runs the code with the constant computations > moved outside the loop in about 94% of the time as the original code, > no matter what optimization settings I try. > > The code wasn't really a bottleneck, I'm just trying to learn to write > lisp in a way that wouldn't make experts cringe. (Apparently the > "ugly and slow" eval version would fall in that category :) ) Yes, but not just because it's ugly and slow: more importantly, it won't work. EVAL evaluates its argument in an empty lexical environment, which means that your variables `fn' and `x' won't be visible. Alberto
First
|
Prev
|
Pages: 1 2 Prev: declaring 'ignore' inside a loop using destructuring Next: The Best gift for this year christmas day! |