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

[REBOL] Re: a new switch-like flow-control function

From: joel:neely:fedex at: 19-Dec-2003 13:57

Hi, Maxim, There's more to the story, although YMMV... Maxim Olivier-Adlhoch wrote:
> describe: func [x [integer!] y [integer!]] [ > switch true compose [ > (x = 1) ["X is one"] > (y = 1) ["Y is one"] > (x = 2) ["X is two"] > (y = 2) ["Y is two"] > (true) ["X and Y are too big!"] > ] > ] > > ... (its also 10% faster, on my computer). >
The timing comparison (even for the trival example I gave) is *highly* dependent on the range of values which X and Y take! The issue is that PIF will evaluate only enough guards to find the first true one, while the SWITCH TRUE COMPOSE approach evaluates *all* guards (and constructs a new block) every time. If e.g. your timing test looks like t0: now/time/precise loop somebignumber [ for x 1 hi 1 [ for y 1 hi 1 [ describe x y ] ] ] t1: now/time/precise print to-decimal t1 - t0 then using HI: 3 will give very different ratios between the two approaches than HI: 6 or HI: 20 etc. PIF allows the programmer easily to follow the standard heuristic of making cheap (or high-probability) tests early to reduce the average cost of a decision-driven expression, e.g.: dihedral-signum: func [ x [number!] y [number!] z [number!] ][ pif [ x <= 0 [0] y <= 0 [0] z <= 0 [0] 10 < square-root abs ( x * (x + 1) * y * (y + 1) * z * (z + 1) - ((x + 2) * (y + 3) * (z + 4)) ) [1] true [-1] ] ] Also, PIF allows the programmer to use failure of earlier tests as guards for the evaluation of later tests, which is another useful (and easy to read/write/understand) technique which the SWITCH TRUE COMPOSE doesn't support: fuel-economy: func [ fuel [number!] distance [number!] ][ pif [ fuel <= 0 ["No data"] distance / fuel < 20 ["Poor fuel economy!"] distance / fuel > 40 ["Great fuel economy!"] true ["Acceptable fuel economy"] ] ] In the above case, we can only reasonably make the later tests if the test FUEL <= 0 has failed. In case anyone is tempted to redesign the tiny examples above, please remember that those are off-the-cuff examples, and they aren't the point! The point is that there's inherent economy in only evaluating enough expressions to get a result (instead of every possible one and then picking the winner), and there are inherent safety and simplicity considerations in knowing that a test can only be evaluated if the previous ones have failed. ON THE OTHER HAND ... If I wanted to resurrect the discussion of a non-deterministic choice among multiple options, I'd be very grateful that you provided a nice way to express that!!! nif: func [[throw catch] b [block!] /local options] [ options: copy [] foreach [guard option] compose b [ if guard [append options option] ] do random/only options ] e.g. from among the guard/action pairs with true guard, evaluate an arbitrarily-chosen action, so that nif [ (x <= y) [x] (y <= x) [y] ] nicely expresses that if X and Y are equal, then either one can be used as the minimum of the two! Thanks! -jn- -- ---------------------------------------------------------------------- Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446 Enron Accountingg in a Nutshell: 1c=$0.01=($0.10)**2=(10c)**2=100c=$1