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


-- 
To unsubscribe from this list, just send an email to
[EMAIL PROTECTED] with unsubscribe as the subject.

Reply via email to