Rebol/Core User's Guide
[1/8] from: lmecir::geocities::com at: 11-Oct-2000 13:11
Hi List! Sorry for the length, but some may be interested, I hope...
Variables:
[Quote]
A variable refers to a specific value only within a defined context, such as
a block, a function, or an entire program.
[End Quote]
That seems to be in contradiction with:
>> probe block
[a a a]
== [a a a]
>> do probe first block
a
== 1
>> do probe second block
a
** Script Error: a has no value.
** Where: do probe second block
>> do probe third block
a
== 2
Words:
[Quote]
For example, -1 and +1 are numbers, not words.
[End Quote]
The following exceptions to the rule might be interesting:
>> type? probe to word! "-1"
-1
== word!
>> type? probe to word! "+1"
+1
== word!
>> type? probe to word! "{"
{
== word!
>> type? probe to word! "[test]"
[test]
== word!
>> type? probe to word! "@#$%^,"
@#$%,
== word!
>> type? probe to word! {
{ }
== word!
>> type? probe to word! ":a"
:a
== word!
>> type? probe to word! "a:"
a:
== word!
>> type? probe to word! "a/v"
a/v
== word!
>> type? probe to word! "'a"
'a
== word!
[Quote]
Word Format
word
REBOL's Treatment
Evaluates the word. This is the most natural and common way to write words.
If the word holds a function, it will be evaluated. Otherwise, the value of
the word will be returned.
[End Quote]
I see the following exceptions to this rule:
1) If the word holds a set-word, the corresponding word is set.
2) If the word holds a lit-word, the corresponding word is returned.
3) If the word holds a path, the path is evaluated and the result of the
evaluation is returned.
4) If the word holds a lit-path, the corresponding path is returned.
5) If the word holds a paren, the paren is evaluated and the result of the
evaluation is returned.
6) If the word holds a set-path, the corresponding path is set.
7) If the word is unset, an error occurs.
Series:
page 5-2
[Quote]
A series is a set of values organized in a specific order.
[End Quote]
The problem with this definition is, that it is a little bit incorrect. The
reason is as follows:
Let's have two mathematical sets: {0} (a set containing zero) and {0,1} (a
set containing zero and one). It is obvious, that these are different sets.
As opposed to this, it is not a problem to have one Rebol series, that
contains only zero and change it to contain both zero and one:
series: [0]
append series 1
series
That is why the correct definition of the series should take into account,
that a series is an ordered container used when we want to store/retrieve
Rebol values.
[Quote]
The first position of the block is called its head.
[End Quote]
This is incorrect, as can be seen here:
block: next [1 2 3 4]
>> first block
== 2
But:
>> first head block
== 1
I would use a little bit different definition:
Every series has got a position (an integer number), that can be obtained as
follows:
index? series
Series with position 1 is called head.
[Quote]
The last position is called tail.
[End Quote]
I would prefer a more consistent wording, e.g.:
A series can have a subseries having a higher position. The smallest
possible subseries of a series is a series with the highest possible
position containing no elements, which is called its tail. The position of
the tail is the length of the head series plus one.
page 5-6
[Quote]
Now the 'colors variable is resting at the tail of the block.
...
print tail? colors
false
[End Quote]
An error, IMO. It should be True.
page 5-36
[Quote]
Although 'str is a local variable, its string value is global.
[End Quote]
[My Favourite Wording]
Although 'str is a local variable, initialized every time Print-it is
evaluated, its string value is contained (or referenced?) in the body of
Print-it and therefore persistent as long as Print-it exists, or at least as
long, as its body references the string in question.
[End My Favourite Wording]
The main reason for suggesting the changed formulation is, that a sentence:
... string value is global...
Doesn't have any meaning a common user (e.g. me) could understand. (How can
I tell a
global string
from "a local one"?)
page 5-64
[Quote]
Multiple variables can refer to the same series.
[End Quote]
The above wording underlines variables, but there are other means how to
obtain a series (a function result, e.g. Next Series, an element of another
series,...)
[My Favourite Wording]
Multiple Rebol series can be the subseries of the same head series.
[End My Favourite Wording]
Scope of Variables
page 8-30 REBOL/Core User Guide Version 2.3
[Quote]
For example, here is a signed if function that evaluates one of three blocks
based on
the sign of a conditional value:
ifs: func [
"If positive do block 1, zero do block 2, minus do 3"
condition block1 block2 block3
][
if positive? condition [return do block1]
if negative? condition [return do block3]
return do block2
]
print ifs 12:00 - now/time ["morning"]["noon"]["night"]
night
[End Quote]
The above definition doesn't work correctly, because it doesn't have the
Throw attribute.
[Corrected version]
ifs: func [
"If positive do block 1, zero do block 2, minus do 3"
[throw]
condition block1 block2 block3
][
either positive? condition [do block1] [
either negative? condition [do block3] [do block2]
]
]
print ifs 12:00 - now/time ["morning"]["noon"]["night"]
morning
[End Corrected Version]
Object Functions
[Quote]
In the case of the bank-account object, the functions for deposit and
withdraw can be added to the current definition:
bank-account: make bank-account [
deposit: func [amount [money!]] [
balance: balance + amount
]
withdraw: func [amount [money!]] [
either negative? balance [
print ["Denied. Account overdrawn by"
absolute balance]
][balance: balance - amount]
]
]
In the example, notice that the functions are able to refer to the balance
directly
within the object. That's because the functions are part of the object's
context.
[End Quote]
I don't like the formulation: "...the functions are part of the object's
context...". The functions surely use words like '+, '-, 'either, which
aren't part of the object's context (are they?), moreover, I am sure I don't
even know, what that should mean.
Objects
Referring to Self
9-12 REBOL/Core User Guide Version 2.3
[Quote]
Every object includes a predefined variable called self. Within the context
of an
object, the self variable refers to the object itself. It can be used to
pass the object
to other functions or to return it as a result of a function.
[End Quote]
The above is true with the following exception:
o: make object! [a: 11]
o/self: 12
-Ladislav
[2/8] from: joel:neely:fedex at: 11-Oct-2000 10:34
Hi, Ladislav,
I haven't finished thinking through all of your comments, but one issue
jumped out at me so forcefully that I thought I'd go ahead and comment
on it...
[lmecir--geocities--com] wrote:
[...snip...]
> Scope of Variables
> page 8-30 REBOL/Core User Guide Version 2.3
<<quoted lines omitted: 28>>
> morning
> [End Corrected Version]
It's also incorrect because it assumes that successive uses of the argument
called condition will produce identical values! Consider this:
>> a: 1
== 1
>> b: to-paren [a: 0 - a]
== (a: 0 - a)
>> ifs b ["positive"] ["negative"] ["zero"]
== "zero"
(simply demonstrating, once again, the severe subtlety of REBOL!)
-jn-
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
[3/8] from: lmecir:geocities at: 11-Oct-2000 18:08
Hi Joel,
I knew about that issue, but considered the Throw attribute as absolutely
necessary in this case (the chapter follows the one describing Throw/Catch
attributes AFAIR). 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]
]
]
Regards
Ladislav
[4/8] 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:
<<quoted lines omitted: 10>>
> ]
> ]
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}
[5/8] from: lmecir:geocities at: 11-Oct-2000 20:38
Hi Joel,
you wrote:
> 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.
<<quoted lines omitted: 37>>
> I had expected that the argument type check would barf on my little
> pathological case, but it didn't!!!!!
You should read exception #5 for word evaluation of my Rebol/Core User's
Guide Comments to understand the behaviour. The fact is, that Ifs really
gets a
number and there is no need to worry about any change during the Ifs
evaluation in the case you supplied and, moreover, if Ifs is defined as
above, no such bug is lurking behind the scenes.
[6/8] from: joel:neely:fedex at: 11-Oct-2000 15:12
Right, again, Ladislav! ;-)
[lmecir--geocities--com] wrote:
> Hi Joel,
> you wrote:
<<quoted lines omitted: 27>>
> User's Guide Comments to understand the behaviour. The fact is, that
> Ifs really gets a number
You're right... I should have thought more carefully about how the
type check would deal with the paren! value supplied.
However, I didn't follow the next comment at all.
> and there is no need to worry about any change during the Ifs
> evaluation in the case you supplied and, moreover, if Ifs is
> defined as above, no such bug is lurking behind the scenes.
>
In the case I supplied, the multiple evaluation DOES cause a bug (or
did I misunderstand you?) as can be seen in the results of "zero",
which occurred every other time. That failure mode occurs when the
evaluation of b returns -1 during the positive? condition test
and then returns 1 during the subsequent negative? condition test,
thus failing both and falling through to the last alternative (which
presumably represents a zero argument value). The supplied argument,
in fact, NEVER evaluates to zero; by alternating between positive and
negative one on subsequent re-evaluations, it can "fake out" any of
the earlier implementations of ifs (the ones that don't evaluate
it once, saving the result).
OBTW, I'm still very interested in whether you have any light to shed
on why the two versions of ifs below behave differently.
> >
> > ifs: func [[throw] ce b1 b2 b3 /local cf] [
<<quoted lines omitted: 18>>
> > == "negative"
> >
versus
> >
> > ifs: func [[throw] cexp pblk zblk nblk /local cval] [
<<quoted lines omitted: 15>>
> > argument!!!!!
> >
Thanks!
-jn-
--
; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677
REBOL [] print to-string debase decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
[7/8] from: g:santilli:tiscalinet:it at: 12-Oct-2000 11:29
[joel--neely--fedex--com] wrote:
> I had expected that the argument type check would barf on my little
> pathological case, but it didn't!!!!!
It doesn't for the simple reason that:
>> type? :b
== paren!
>> probe :b
(a: negate a)
== (a: negate a)
>> type? b
== integer!
>> probe b
-1
== -1
So you're actually passing an integer, not a paren, to IFS.
> so you can imagine my surprise to obtain these results!
[...]
You're still passing an integer, here. (You get "zero" because you
have written IFS as:
ifs: func [[throw] cexp pblk zblk nblk /local cval] [ ...
notice PBLK ZBLK NBLK instead of PBLK NBLK ZBLK.)
> Well, it appears that do does NOT distribute over evaluation of its
> argument!!!!!
It does, don't worry. :-)
Anyway, let me partecipate with my own version:
>> sign: func [num [number!]] [either zero? num [0] [divide num abs num]]
>> sign 2
== 1
>> sign -2
== -1
>> sign 0
== 0
>> ifs: func [
[ [throw]
[ num [number!]
[ if-pos [block!]
[ if-zero [block!]
[ if-neg [block!]
[ ] [
[ do get pick [if-neg if-zero if-pos] add 2 sign num
[ ]
>> ifs -2 ["positive"] ["zero"] ["negative"]
== "negative"
>> ifs 0 ["positive"] ["zero"] ["negative"]
== "zero"
>> ifs 2 ["positive"] ["zero"] ["negative"]
== "positive"
Seems to work as expected. With B also:
>> ifs b ["positive"] ["zero"] ["negative"]
== "positive"
>> ifs b ["positive"] ["zero"] ["negative"]
== "negative"
>> ifs b ["positive"] ["zero"] ["negative"]
== "positive"
Notice that:
>> ifs :b ["positive"] ["zero"] ["negative"]
** Script Error: ifs expected num argument of type: number.
** Where: ifs :b ["positive"] ["zero"] ["negative"]
Different,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[8/8] from: joel:neely:fedex at: 12-Oct-2000 8:02
[giesse--dsiaq1--ing--univaq--it] wrote:
> [joel--neely--fedex--com] wrote:
> > I had expected that the argument type check would barf on my little
<<quoted lines omitted: 11>>
> == -1
> So you're actually passing an integer, not a paren, to IFS.
Yes. It finally sunk in... ;-)
> > so you can imagine my surprise to obtain these results!
> [...]
<<quoted lines omitted: 5>>
> > argument!!!!!
> It does, don't worry. :-)
I'm delighted to stand corrected. To quote someone from an earlier
post, "Silly me!"
> Anyway, let me partecipate with my own version:
> >> sign: func [num [number!]] [either zero? num [0] [divide num abs num]]
<<quoted lines omitted: 4>>
> >> sign 0
> == 0
Nice! Let me further suggest
signum: func [val [number! char! money! time!]] [
either zero? val [0] [either negative? val [-1] [1]]]
The change of name is suggested to reduce reading-aloud confusion
betweeen "sign" and "sine" -- from an old math textbook.
The replacement of your elegant division with more explicit logic
is to allow the domain to include all argument types accepted by
Positive? , Negative? , and Zero? .
> >> ifs: func [
> [ [throw]
<<quoted lines omitted: 5>>
> [ do get pick [if-neg if-zero if-pos] add 2 sign num
> [ ]
An elegant solution to the multiple-evaluation problem! My
compliments!
> >> ifs -2 ["positive"] ["zero"] ["negative"]
> == "negative"
<<quoted lines omitted: 13>>
> ** Script Error: ifs expected num argument of type: number.
> ** Where: ifs :b ["positive"] ["zero"] ["negative"]
Inspired by your Ifs above, let me offer to remove the type
constraint...
ifs: func [
[throw]
num if-pos [block!] if-zero [block!] if-neg [block!]
][
do get pick [if-neg if-zero if-pos] add 2 signum num]
...provide another pathological B ...
>> a: 1 == 1
>> b: to-paren [a: a + 2 // 3 - 1] == (a: a + 2 // 3 - 1)
<<quoted lines omitted: 4>>
>> b == 0
>> b == 1
Which seems to work both with B and :B ...
>> ifs b ["pos"] ["zero"] ["neg"] == "neg"
>> ifs b ["pos"] ["zero"] ["neg"] == "zero"
>> ifs b ["pos"] ["zero"] ["neg"] == "pos"
>> ifs :b ["pos"] ["zero"] ["neg"] == "neg"
>> ifs :b ["pos"] ["zero"] ["neg"] == "zero"
>> ifs :b ["pos"] ["zero"] ["neg"] == "pos"
-jn-
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted