Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

[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" ;