[REBOL] Re: ALL and ANY words
From: joel:neely:fedex at: 1-Feb-2003 10:09
Hi, Philippe,
TMTOWTUT -- There's more than one way to use them...
(with apologies to Perlophobes ;-)
Philippe Oehler wrote:
> Ok.. I understand now.. With ALL, you can make a lots of stuff,
> with conditions checks, and break opportunities, without using
> long structures of IF.. it's cool
>
ALL can play the role of a generalized AND ...
all [a b c ... z]
evaluates A and B and C and ... Z in order, but quits as soon as
a FALSE or NONE value is encountered (in which case it returns
NONE -- instead of FALSE, which is a bit counter-intuitive IMHO).
<MILDSURPRISE>
UNSET! is neither FALSE nor NONE, and therefore allows ALL
to continue evaluation, as in
>> type? all [print 1 print true print false]
1
true
false
== unset!
</MILDSURPRISE>
Given that the expression
if cond expr
yields NONE if COND evaluates false, and otherwise the value of
evaluating EXPR, ALL can be combined with IF in interesting ways:
>> a: 1 b: 2 c: 3
== 3
>> if all [
[ if a < b [print "a:b in order"]
[ if b < c [print "b:c in order"]
[ true
[ ] [print "all in order"]
a:b in order
b:c in order
all in order
>>
IOW, ALL can be used to sequence/control subordinate actions, with
bailout
conditions to interrupt/abort the sequence of actions.
As for ANY, it can serve as a generalized OR, as in:
any [a b c ... z]
which quits as soon as a value that is neither FALSE nor NONE is
encountered in evaluation (same MILDSURPRISE previously noted
applies here as well).
Therefore a common idiom is to use ANY to establish default values.
var: any [expr0 expr1 ... defaultexpr]
so that the first subexpression that yields a (non-FALSE, non-NONE)
value will supply the value for VAR, and DEFAULTEXPR will supply the
one if no others work:
class: any [
if find seniors studentID ["senior"]
if find juniors studentID ["junior"]
if find sophomores studentID ["sophomore"]
if find freshmen studentID ["freshman"]
"unregistered"
]
One (slightly contrived) example is to detect cases where variables
have (intentionally) never been initialized, as in the infamous
first time through a loop
case. Suppose we want to determine
whether a block of numbers is in ascending order. We could write
this in a fairly boring way:
catch [
use [old] [
old: block-o-nums/1
foreach new block-o-nums [
if new < old [throw false]
old: new
]
true
]
]
or use ANY to handle the initialization issue for us:
catch [
use [old] [
old: none
foreach new block-o-nums [
if new < any [old new] [throw false]
old: new
]
true
]
]
(I said it was contrived! ;=-) The point is that we can use ANY and
ALL to do all sorts of interesting tricks. Having options is nice!
-jn-