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

a new switch-like flow-control function

 [1/13] from: antonr::iinet::net::au at: 18-Dec-2003 1:00


I yearn (want), occasionally, a kind of any/switch-like flow-control function. What I came up with (works ok) is similar in function to what I want: do select reduce [ condition-1 [...] condition-2 [...] true [...] ; default code ] true It's kind of like ANY, in that it does the code associated with the first condition that returns true. I used it in a feel/detect function like so.. do select reduce [ event/shift [...] event/control [...] true [...] ; default ] true to handle shift-clicks, control-clicks and plain mouse clicks. But I would like it to be more like ANY. In ANY, the first evaluated value that is not none is considered "true" and returned. In the desired function, the first evaluated condition that is not none should have its associated code executed. (That's different to the above - conditions have to evaluate to true.) I should use such a function like this: any-switch [ condition-1 [...] condition-2 [...] true [] ] Hmm, maybe it should be a refinement:- switch/any ? On another note, today I had the occasion to write: face/parent-face/parent-face/parent-face/parent-face/parent-face Don't ask me the object hierarchy that leads to that expression. :) Anton.

 [2/13] from: joel:neely:fedex at: 17-Dec-2003 10:19


Hi, Anton, Set the WayBack machine to 2000... ;-) Anton Rolls wrote:
> I yearn (want), occasionally, a kind of any/switch-like > flow-control function...
Some years ago we had a long discussion about generalizing IF on the list, and kicked around various options/versions. The copy I could lay my hands on most quickly was Ladislav's refinement (the last in the discussion???): pif: func [[throw catch] args [block!] /local res] [ either unset? first res: do/next args [ if not empty? args [ throw make error! [script no-arg pif condition] ] ][ either first res [ either block? first res: do/next second res [ do first res ][ throw make error! [ script expect-arg pif block [block!] ] ] ][ pif second do/next second res ] ] ] PIF (Polymorphic IF) takes a block of guard-expression/block pairs and uses the (first true) guard-expressions to select block to be evaluated. It can be used (I believe) essentially as you were asking. Refactoring PIF to iterative form is left as an exercise for the reader! ;-) As long as the argument block isn't too long the recursion likely won't be a problem. Heres a sample usage: describe: func [x [integer!] y [integer!]] [ pif [ 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!"] ] ] which behaves as:
>> describe 1 1
== "X is one"
>> describe 2 1
== "Y is one"
>> describe 2 2
== "X is two"
>> describe 3 2
== "Y is two"
>> describe 3 3
== "X and Y are too big!" -jn- -- ---------------------------------------------------------------------- Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446 Enron Accountingg in a Nutshell: 1c=$0.01=($0.10)**2=(10c)**2=100c=$1

 [3/13] from: g:santilli:tiscalinet:it at: 18-Dec-2003 10:52


Hi Anton, On Wednesday, December 17, 2003, 3:00:06 PM, you wrote: AR> do select reduce [ AR> event/shift [...] AR> event/control [...] AR> true [...] ; default AR> ] true any [ if event/shift [... true] if event/control [... true] (...) ] Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/

 [4/13] from: antonr:iinet:au at: 19-Dec-2003 1:58


Thanks Joel, I think this is just what I need. I don't think pif is a good name for it, though, it reminds me of obscure unix commands, not very rebolish. But what is a good name? Perhaps something like "reselect" (because it's a bit like a select reduce, but since that's not strictly true, then that could confuse more..) ? How about "any-select" ? (Guh, same problem) Here's some ideas: http://thesaurus.reference.com/search?q=select - satisfy, select-if, do-elect ... I don't think there is a good word. - poly-if <- that is my favourite so far. Anton.

 [5/13] from: maximo:meteorstudios at: 19-Dec-2003 12:10


sorry for being late, but note that this works, straight out of the box: 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!"] ] ] notice that its as easy to use as pif (its also 10% faster, on my computer).
>> describe 1 1
== "X is one"
>> describe 2 1
== "Y is one"
>> describe 2 2
== "X is two"
>> describe 3 2
== "Y is two"
>> describe 3 3
== "X and Y are too big!" -Max

 [6/13] 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 [
<<quoted lines omitted: 6>>
> ] > ... (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

 [7/13] from: antonr:iinet:au at: 21-Dec-2003 14:35


Actually, I will change it to your suggestion for this situation, because with only two/three cases to select from, it is more efficient code. do select reduce [...] is only better in code-size for > ~8 cases. Anton.

 [8/13] from: antonr:iinet:au at: 21-Dec-2003 14:49


Oops, should be > 3 cases. Anton.

 [9/13] from: alain:goye:free at: 22-Dec-2003 11:41


Hello all from a newcomer to this list, Here is a function for only 1 condition but 3 cases : if it can be useful to anyone trif: func [ condition iftrue [block!] iffalse [block!] ifnone [block!] ] [ do either condition [ iftrue ] [ either none? condition [ ifnone ] [ iffalse ] ] ] ; example: print trif request "give an answer" ["yes"]["no"]["cancel"] by the way, is it good that "not none" equals "true" ? Alain Goyé.

 [10/13] from: lmecir:mbox:vol:cz at: 23-Dec-2003 16:59


Hi Alain,
>Here is a function for only 1 condition but 3 cases : if it can be >useful to anyone
<<quoted lines omitted: 5>>
>is it good that "not none" equals "true" ? >Alain Goyé.
yes, it is useful. The following improvement uses the [throw] attribute to make the behaviour of the function more standard with respect to Return: trif: func [ {Three case if} [throw] condition iftrue [block!] iffalse [block!] ifnone [block!] ] [ do either condition [ iftrue ] [ either none? condition [ ifnone ] [ iffalse ] ] ] ; example: f: does [trif request "give an answer" [return "yes"] [return "no"] [return "cancel"] "Shoudn't get here"] Merry Christmas -Ladislav

 [11/13] from: greggirwin:mindspring at: 23-Dec-2003 9:21


AG> Hello all from a newcomer to this list, Welcome Alain! AG> Here is a function for only 1 condition but 3 cases : if it can be AG> useful to anyone AG> trif: func [ AG> condition AG> iftrue [block!] AG> iffalse [block!] AG> ifnone [block!] For more standard REBOL style, you might consider using hyphens to separate words. e.g. if-true [block!] if-false [block!] if-none [block!] You could also use PICK in place of a second either: trif: func [ condition if-true [block!] if-false [block!] if-none [block!] ] [ do either none? condition [if-none] [pick [if-true if-false] condition] ] Using PICK this way isn't always the clearest choice, but sometimes it can be quite handy. AG> by the way, AG> is it good that "not none" equals "true" ? I think so. What else would you have it return? Thanks for posting! -- Gregg

 [12/13] from: patrick:philipot:laposte at: 23-Dec-2003 17:39


Hi List, What is the meaning of thro? I have seen it here and there but never quite understood its purpose. Regards Patrick

 [13/13] from: lmecir:mbox:vol:cz at: 23-Dec-2003 19:21


Hi Pat,
>What is the meaning of thro? >I have seen it here and there but never quite understood its purpose.
<<quoted lines omitted: 32>>
>> >[return "cancel"] "Shoudn't get here"]
Try to use the version of the above function without the [throw] attribute and you will find out, that the result of F will be: == "Shoudn't get here" , which indicates, that the Return got "consumed" by Trif , while what we intended was to "throw" Return to F. The "throw" attribute does exactly that - throws Return to caller functions. Merry Christmas -Ladislav

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted