[REBOL] Rebol/Core User's Guide Re:(3)
From: joel:neely:fedex at: 11-Oct-2000 12:42
Hello again, Ladislav,
[lmecir--geocities--com] wrote:
> Hi Joel,
>
> I knew about that issue, but considered the Throw attribute as absolutely
> necessary in this case...
>
Certainly! I've been reading a fascinating essay by Richard Gabriel on the
power (and dangers!) of abstraction, and will likely mutter about that in
a later post.
> You are right. To be correct, it should have been like
> this:
>
> ifs: func [
> {If positive do block 1, zero do block 2, minus do 3}
> [throw]
> condition [number!]
> block1 [block!]
> block2 [block!]
> block3 [block!]
> ] [
> either positive? condition [do block1] [
> either negative? condition [do block3] [do block2]
> ]
> ]
>
Well, I was as surprised as you will be by the following behavior:
>> ifs: func [
[ {If positive do block 1, zero do block 2, minus do 3}
[ [throw]
[ condition [number!]
[ block1 [block!]
[ block2 [block!]
[ block3 [block!]
[ ] [
[ either positive? condition [do block1] [
[ either negative? condition [do block3] [do block2]
[ ]
[ ]
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero"
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero
I had expected that the argument type check would barf on my little
pathological case, but it didn't!!!!!
However, I accept fault for typing and hitting "Send" too quickly without
explaining my interest in the issue of expressions with side effects.
(So no-one has to backtrack in the thread, let me repeat the definitions and
usage of
>> a: 1
== 1
>> b: to-paren [a: 0 - a]
== (a: 0 - a)
>> b
== -1
>> b
== 1
>> b
== -1
>> b
== 1
for use below)
I was actually wondering about allowing a more general type of argument,
but writing ifs in such a way as to "freeze" the value with one
evaluation, then re-use that frozen, evaluated-once-only value as often
as necessary. I tried a little experiment with this variation:
ifs: func [[throw] ce b1 b2 b3 /local cf] [
either positive? cf: ce [
do b1
][
either negative? cf [
do b2
][
do b3
]
]
]
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "negative"
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "negative"
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
Aha! This captures the side-effects avoidance nicely. (I think I have
permuted the argument list here, but that's irrelevant to the main point
I'm pursuing, so I didn't bother to fix that inconsistency.)
Notice that the above definition uses cryptic argument names. It also
is simply selecting which of the three blocks to do as the chosen
activity. Therefore, I expected it to be equivalent to the nicer
ifs: func [[throw] cexp pblk zblk nblk /local cval] [
do either positive? cval: cexp [pblk] [
either negative? cval [nblk] [zblk]
]
]
so you can imagine my surprise to obtain these results!
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero"
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero"
>> ifs b ["positive"] ["negative"] ["zero"]
== "positive"
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero"
Well, it appears that do does NOT distribute over evaluation of its
argument!!!!!
Comments welcomed!
-jn-
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}