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

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