[REBOL] Re: Translate this code into real Rebol?
From: joel:neely:fedex at: 23-Jan-2002 20:52
Hi, Jeff,
Perhaps you can shed some light on a couple of questions...
Jeff Kreis wrote:
> Similarly, I "piggy-back" all the word setting together,
> (except for the three user-vars which I left at the top).
>
I did some test a while back that indicated that
set [word1 word2 word3 ... wordN] reduce [
expression1
expression2
expression3
...
expressionN
]
takes a surprising performance hit compared with
word1: expression1
word2: expression2
word3: expression3
...
wordN: expressionN
(example in footnote below). I'm very fond of the idea of
concurrent assignment
(or whatever other term one would
prefer) for a variety of reasons, but have a hard time with
the performance penalty.
Is it reasonable to believe that the majority of the extra
time required by the block SET is due to REDUCE -- specifically
the time required to allocate, and store values in, a new block?
Is there any hope of a "special form" or other means of
avoiding the cost penalty?
> Now, Joel may benchmark these functions and demonstrate that
> my code is not the optimal solution. (-:
>
Time isn't the only measure of optimality; readability also
counts for something! ;-)
> This is likely because of the inner functions among other
> things. Inner functions are used when you want to share
> context, but in the case above, I defined them inside the
> function because they go with its "thinking". They'll likely
> be a performance hit, though (among other things).
>
I'm also fond of using inner functions as a way to package
meaningful chunks of sub-computations without polluting the
enclosing namespace, but have pondered how to get those
benefits without the cost of (inner) function definition for
every (outer function) evaluation. One idea that I've played
with is employing USE to hide the helper(s), as in
fibonacci: use [fibohelp] [
fibohelp: func [n [integer!] /local a b] [
a: 0 b: 1
while [n > 0] [a: (b: b + a) - a n: n - 1]
a
]
func [n [integer!]] [
either all [negative? n even? n] [
- fibohelp abs n
][
fibohelp abs n
]
]
]
which allows the helper to be defined once for all, instead
of redefining it every time the parent is evaluated.
Of course, this has the drawback it doesn't allow the
(formerly inner) helper function access to the outer function's
namespace. This limitation can be fixed by placing the shared
words within the USE context, but then that has really nasty
consequences on recursion!
Any thoughts on how to get the benefits of inner functions
(nice "packaging" and communication of ideas, maximum locality,
minimizing global namespace impact, shared context) without
the overhead of redefinition on every use?
-jn-
8<------------------------------------------------------------
Footnote: The following functions demonstrate the extra
time required for block SET, and provide some evidence that
REDUCE is the culprit.
; set three words to trivial expressions via block SET
bset3: func [n [integer!] /local t0 w0 w1 w2] [
t0: now/time/precise
repeat i n [set [w0 w1 w2] reduce [i i i]]
now/time/precise - t0
]
; set three words to trivial expressions individually
iset3: func [n [integer!] /local t0 w0 w1 w2] [
t0: now/time/precise
repeat i n [w0: i w1: i w2: i]
now/time/precise - t0
]
; set one word to a block of trivial expressions
setb3: func [n [integer!] /local t0 w0] [
t0: now/time/precise
repeat i n [w0: reduce [i i i]]
now/time/precise - t0
]
; "chain" set three words to a trivial expression
cset3: func [n [integer!] /local t0 w0 w1 w2] [
t0: now/time/precise
repeat i n [w0: w1: w2: i]
now/time/precise - t0
]
>> print [cset3 1000000 iset3 1000000 setb3 1000000 bset3 1000000]
0:00:02.96 0:00:04.34 0:00:22.41 0:00:27.9
CSET3 provides a baseline for the overhead of the loop and the three
set-words. The additional time required by ISET3 is due to the two
additional evaluations of I. REDUCEing a block of three occurrences
of I takes about 5 times as much time as evaluating I three times.
Doing the block SET bumps the time up further (this increase alone
is more than the total time for the three set-word version).
--
; sub REBOL {}; sub head ($) {@_[0]}
REBOL []
# despam: func [e] [replace replace/all e ":" "." "#" "@"]
; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"}
print head reverse despam "moc:xedef#yleen:leoj" ;