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

On ordinal and cardinal numbers...

 [1/47] from: g::santilli::tiscalinet::it at: 6-Jul-2001 18:55


(Dedicated to Jeff and Joel :) I didn't want to partecipate to the "indexing" thread... but I couldn't resist pointing out my point of view. I promise I'll keep this message as short as possible; I'll send a personal mail with all the reasoning for the following to anyone that really wants to read such a thing. :-) - Ordinal numbers and Cardinal numbers are different things. I see everyone here seems to confuse the two concepts. The set of cardinal (i.e. natural) number is {0, 1, 2, 3, ...} and is defined by the axioms presented by Joel. The set of ordinal numbers has nothing to do with the above, and is {1st, 2nd, 3rd, ...}. Jeff, please notice that the set of ordinal numbers does not contain the symbol 0th or zeroeth. This monster exists for other reasons, which I think I can explain if you want. - The two sets above CAN be put in 1-1 relationship. The common 1-1 relationship between the two is {(0, 1st), (1, 2nd), (2, 3rd), ...} which says that 0 is the first natural number, 1 is the second natural number, and so on. Please notice that REBOL perfectly agrees with this:
>> N: [0 1 2 3 4 5 6 7 8 9 10 11 12] ; and so on... imagine this being infinite
== [0 1 2 3 4 5 6 7 8 9 10 11 12]
>> first N
== 0
>> second N
== 1
>> third N
== 2 Again, Jeff: 0 is not the zeroeth natural number. It is the FIRST natural number, as REBOL correctly reports. - REBOL's series functions are perfectly consistent as long as you view them in the right prospective. PICK does not accept a natural number as is second arguments; it requires an ordinal number instead. (Pity REBOL does not include an ordinal! datatype, of course Carl thought it was superflous to add since the set of ordinal numbers can be represented by a subset of the set of natural numbers (i.e. N - {0}); unfortunately this seemed to create a certain confusion amongst REBOL users.) Actually, REBOL's series function use a generalization of ordinal numbers, because in REBOL positions can be considered both by "looking forward" and by "looking backward" from the current series "index" (or maybe I should use the term "cursor"?). The first element "looking forward" is represented by the symbol 1st, while the first element "looking backward" is represented by the symbol -1st. So the set of ordinal numbers is actually for REBOL: {... -3rd, -2nd, -1st, 1st, 2nd, 3rd, ...} which REBOL represents using the subset of Z: {... -3, -2, -1, 1, 2, 3, ...} This set DOES NOT contain 0. So it is perfectly consistent for PICK to fail on a second argument of 0, since 0 IS NOT an ordinal number. - Other languages do not really have a concept of "series" which is a more general concept than that of vector or array; also, other languages tend to use relative positioning of elements inside vectors, while REBOL's series use absolute positioning using ordinal numbers. You can't just say that absolute positioning is wrong, while relative is right. (Note for Ladislav: of course PICK and AT are not 0 based nor 1 based; they do not use relative positioning!) Also, REBOL allows relative positioning too, thru the function SKIP. So, in the case where you really need a PICK function that accepts an integer as its second argument (considering it as a distance to the first element of the series) you can use: my-pick: func [series offset] [pick skip series offset 1] (Ok, I'll shut up now... this is already way too long!) Not 0 based nor 1 based, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [2/47] from: jeff:rebol at: 6-Jul-2001 10:14


> I didn't want to partecipate to the "indexing" > thread... but I couldn't resist pointing out my point of > view.
Thanks, Gabriele: That was instructive. -jeff

 [3/47] from: joel:neely:fedex at: 6-Jul-2001 13:49


Hi, Gabriele, Excellent summary! Gabriele Santilli wrote:
> the set of ordinal numbers can be represented by a subset of > the set of natural numbers (i.e. N - {0}); unfortunately this > seemed to create a certain confusion amongst REBOL users. >
(Not confusion, IMHO, just a plea that there really are some legitimate roles for the poor orphan.) -jn- ___________________________________________________________________ One is the loneliest number... - Three Dog Night joel'dot'neely'at'fedex'dot'com

 [4/47] from: g:santilli:tiscalinet:it at: 6-Jul-2001 21:50


Hello Joel! On 06-Lug-01, you wrote: JN> (Not confusion, IMHO, just a plea that there really are some JN> legitimate roles for the poor orphan.) (I was surely not referring to you about confusion. :) This seems to be 2.3 times slower than pick: ofs-pick: func [series offset] [pick skip series offset 1] The following is only a bit faster, but has a hole in -1 which is way worse that the hole in 0 of pick: ofs-pick: func [series offset] [pick series offset + 1] If you put the code of the first ofs-pick inline, it is only 1.6 times slower (with the + 1 we go down to 1.3); provided the cases in which such code is needed are few, I think the overhead is not that great. Do you think this is worth adding new natives? (I'm really asking!) Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [5/47] from: joel:neely:fedex at: 6-Jul-2001 6:50


Hi, Gabriele, Gabriele Santilli wrote:
> This seems to be 2.3 times slower than pick: > > ofs-pick: func [series offset] [pick skip series offset 1] >
... Nice analysis! (Numbers are good!)
> If you put the code of the first ofs-pick inline, it is only > 1.6 times slower ... provided the cases in which such code > is needed are few, I think the overhead is not that great. > Do you think this is worth adding new natives? (I'm > really asking!) >
I guess "worth" is in the mind of the beholder, but your question inspires a few thoughts: 1) The issue of whether "the cases in which such code is needed are few" is highly dependent on the application. Programs that spend most of their time munching data that has already been plucked from the tree (or other data structure ;-) wouldn't suffer, but those that spend a significant portion of their time navigating would certainly be affected by a 60% increase in time required for basic inner-loop operations. 2) Having to repeat pick skip foo glarp 1 throughout the code sounds like a great opportunity for typos and other such bugs to creep in. 3) Having to reproduce faithfully such expressions when parts are actually replaced by various sub-expressions... pick skip foo index? find quux breeble 1 pick skip baz 3 + length? substruct * 2 1 ...etc... again sounds like lots of potential for obscurity and error. I'm certainly enough of a realist to know that any enhancement has to wait its turn in a prioritized list (with lots of high- urgency competition for limited developer resources). But I'm enough of an idealist to believe that we should be able to discuss such things. Thanks again for your thought -ful and -provoking comments! -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [6/47] from: carl:rebol at: 6-Jul-2001 17:18


First, let me say that as a programmer I do not like one-based math. I've felt that way for more than 20 years. Second, let me ask what is the first paragraph of this email? It is paragraph 1. That's how most of the world sees it. So, there's the rub. Some of you are searching for mathematical purity because you think REBOL is a programming language. REBOL is a language for communication. There are plenty of programming languages out there. Use APL if you want math purity. Use Scheme if you want functional purity, or Prolog if you want logic purity. In REBOL, first = 1 That's the way it is. Sorry if you do not like that. I did not like it. I resisted it for years. I fully understand the singularity it creates in some types of math. That has not been a problem for *most* of the code I write. If you really feel that you need a native or two to deal with it, send me an email with what you want. (If you post it to the list I probably won't see it.) Be sure to provide a good name, since that takes more time than coding. -Carl The guy responsible.

 [7/47] from: agem:crosswinds at: 9-Jul-2001 15:59


RE: [REBOL] Re: On ordinal and cardinal numbers... Hi Larry, Joel, interesting solutions :) [larry--ecotope--com] wrote:
> Hi Joel > > Nice variation on the theme!
<<quoted lines omitted: 13>>
> doubt there are many cases where one is interested in a very large skip on a > small series. Still.. see below.
Tail-recursion-elimination drops to loops by some compilers/interpreters. In that case no overhead. Rebol does not, so Joel prefers iteration. :)
> >> b: make block! 10000 > == []
<<quoted lines omitted: 49>>
> takes one cycle for the iterative version because LOOP falls through (i.e., > the code block does not execute).
with tail-check one can remove something with remove block ring-skip 0 ? round-based game with player drops out for example.

 [8/47] from: kolla:nvg:ntnu:no at: 9-Jul-2001 16:54


On Fri, 6 Jul 2001, Carl Sassenrath wrote:
> In REBOL, first = 1 That's the way it is. Sorry if you do not like > that. I did not like it. I resisted it for years.
First is not always first, take floors in a house for instance. You say first floor, here we say second floor (or rather second etage), our first floor being ground floor. In case anyone does a elivator script, hehe :) -- kolla

 [9/47] from: larry:ecotope at: 9-Jul-2001 12:59


Hi all, Oops, my bad. There was a stupid (and critical) typo in the recursive version, in the function body it called the iterative version RING-SKIP instead of itself, RING-SKIP2.
> The second uses recursion: > ring-skip2: func [s [series!] n [integer!]] [
<<quoted lines omitted: 7>>
> ] > ]
When corrected, the recursive version fails with a stack overflow at a skip value of 1515. The timings where b is a block of 10000 integers and the skip value is 1514 are:
>> t: now/time/precise loop 100 [ring-skip b 1514] now/time/precise - t
== 0:00:00.44
>> t: now/time/precise loop 100 [ring-skip2 b 1514] now/time/precise - t
== 0:00:02.14 So the iterative version is about 5 times faster for the maximum skip value allowed by the recursive version. BTW I get the same results as Mark with his recursion test, a maximum stack depth of 3147. Clearly, as Joel indicated, we should prefer the iterative version, if we anticipate using it on very large series. Sorry for the confusion. -Larry

 [10/47] from: ptretter:charter at: 9-Jul-2001 20:31


Since I'm relatively new at programming, can you explain what is meant by recursion and iteration? I just want to learn ;) Paul Tretter

 [11/47] from: rgaither:triad:rr at: 9-Jul-2001 22:21


Hi Paul,
>Since I'm relatively new at programming, can you explain what is meant by >recursion and iteration? I just want to learn ;)
Recursion is when a function calls itself as part of its processing. http://webopedia.internet.com/TERM/r/recursion.html Iteration is using a loop to repeat a series of program instructions. http://webopedia.internet.com/TERM/I/iteration.html Note - both are ways to repeat the same processing over and over again. FYI, Rod. Rod Gaither Oak Ridge, NC - USA [rgaither--triad--rr--com]

 [12/47] from: dness:home at: 9-Jul-2001 22:02


Ken Anthony wrote:
...
> So you would agree that the moment of midnight belongs to the day that > follows as 12am above suggests?
<<quoted lines omitted: 3>>
> reasonable to vote? I don't think so, but hey I don't want to be different! > Oops! Too late... ;-))
Surely not. The `moment of midnight' is surely too brief to `belong' to anything. In the world pf the astrophysical clock, the `moment of midnight' is surely less than one atomic vibration in duration, and since chaos reigns supreme in the infinitesimal world of time less than atomic vibrations, arguing about it would be like having Canada and the US argue over who owns the land under the 49th Parallel. In total there's 0.00 acres there to worry about just like there's 0.00... seconds to worry about at the `moment of midnight'.

 [13/47] from: kenneth:nwinet at: 9-Jul-2001 21:28


Dave, Thank you for the geographic analogy. I thought it was very good. So your voting for the third scenario, neither. Any of the five scenarios could have there proponents. So how do we come to an agreement? When a day starts is one of those things that is subject to a committee decision which makes it an artificial thing IMHO. Which is to say, it's not something to go to the mat over. However, it is one of those things that barring a political action we can agree on if we choose to. Your saying days are discontinuous at midnight? Doesn't sound good when I put it that way. ;-) Is it only the moment of midnight or any moment that's "too brief to belong to anything?" In other words, would July 9th 12:01am belong to July 9th, but July 9th 12:00am not? Respectfully, Ken.

 [14/47] from: dness:home at: 10-Jul-2001 0:41


Paul Tretter wrote:
> Since I'm relatively new at programming, can you explain what is meant by > recursion and iteration? I just want to learn ;) > > Paul Tretter >
Well the `real' answer to a question like this has been the subject of hundreds if not thousands of PhD theses, so (a) I'll give you the _very short_ answer; and (b) Trust you'll go buy Knuth, Ableson, or any one of a number of basic texts on programming which will at least tell you more. Generally the prototypical answer is to describe the `factorial'. Iteratively, n! = n * (n-1) * (n-2) * ... * 2 * 1 Recursively n! = n * (n-1)! , along with 0! = 1 Either of these defines the factorial, but in the recursive definition, the notion of factorial is, itself, used in the definition.

 [15/47] from: kenneth:nwinet at: 9-Jul-2001 22:31


BTW, Dave, Did you note that you started your measurement of Acres at zero rather than one? ;-) Just an observation. Ken.

 [16/47] from: joel:neely:fedex at: 10-Jul-2001 2:39


Hi, Paul, Paul Tretter wrote:
> Since I'm relatively new at programming, can you explain what > is meant by recursion and iteration? I just want to learn ;) >
Certainly! Iteration is just the conventional jargon for "repetition" (as in "let me re-iterate" instead of "let me repeat"). The words LOOP, FOR, FOREACH, UNTIL, and (of course) REPEAT are all ways of doing iteration in REBOL. Recursion basically means something which is defined in terms of itself, such as a function that calls itself, directly or indirectly. (The standard joke, from the Jargon File, is recursion n. See recursion. See also tail recursion. but we'll cover "tail recursion" a bit later.) Sometimes you also hear reference to "resursive structures", which means structures whose content may be of the same type as the whole structure (e.g. blocks within blocks). Such structures are often processed with -- what else? -- recursive functions. To illustrate, suppose we have a block of numbers:
>> nums: [90 1 45 52 42 19]
== [90 1 45 52 42 19] We can define the sum iteratively as repeat the process add a number to the total until all numbers have been added One iterative solution to adding up the numbers in the block is: tot: 0 foreach num nums [tot: tot + num] tot == 249 If we didn't have the nice handy FOREACH function we could write tot: 0 numref: nums while [not tail? numref] [ tot: tot + first numref numref: next numref ] tot == 249 (among *many* other iterative possibilities). In contrast, if we want to write a recursive solution, we start by defining the sum of a collection of numbers this way: the sum of an empty collection is zero the sum of a non-empty collection is the first number plus the sum of the rest of the numbers which leads us to this recursive solution in REBOL sum-o-nums: func [b [block!]] [ either tail? b [0] [(first b) + sum-o-nums next b] ]
>> sum-o-nums nums
== 249 If we visualize the work of this function, we can get a couple of useful insights. Using a tiny block of numbers, we can work step-by-step through the computation by rewriting: sum-o-nums [2 3 4] (first [2 3 4]) + sum-o-nums next [2 3 4] 2 + sum-o-nums [3 4] = (and now we'll pick up the pace) 2 + (3 + sum-o-nums [4]) 2 + (3 + (4 + sum-o-nums [])) 2 + (3 + (4 + 0)) 2 + (3 + 4) 2 + 7 9 Forgive me if I belabor the obvious, but the key here is that all of the earlier additions are "on hold" until we get all the way to the 0 at the "bottom"; we can then begin the process of resuming the pending additions and working back up to the top answer. The effort of keeping track of partially-completed work (a sort-of "virtual to-do list", managed by the interpreter) is why iteration is usually faster than recursion for simple cases like the example above. On the other hand, some not-so-simple tasks that don't have an obvious iterative solution are fairly easy to express using recursion, such as the case of "pretty-printing" a block structure as an indented "outline": pp: func [b [block!] /local -pp] [ -pp: func [x ind [string!]] [ either block? x [ print [ind "["] foreach y x [-pp y join ind " "] print [ind "]"] ][ print [ind x] ] ] -pp b "" ]
>> pp [2 [3 5 7 [9]] 11 13]
[ 2 [ 3 5 7 [ 9 ] ] 11 13 ] Here the internal functinon -PP invokes itself (with a deeper indentation prefix) to deal with nested blocks, so it is recursive. Keeping track of where we are in the block structure is sufficiently tedious that writing this function recursively is simpler than writing it as an iterative function. Finally, I promised to get back to "tail recursion", which I'm doing at the tail of the email. ;-) Consider this recursive-looking function to sum up our block of numbers. tr-sum: func [b [block!] /local -tr-sum] [ -tr-sum: func [b [block!] s [number!]] [ either tail? b [s] [-tr-sum next b s + first b] ] -tr-sum b 0 ]
>> tr-sum nums
== 249 That inner function -TR-SUM certainly *looks* recursive, because it calls itself. However, that call is done in such a way that there isn't really any "pending" work to do after the recursive call (except for simply returning the result). A really clever compiler (or interpreter) will be able to treat that function as if it had been written this way: ti-sum: func [b [block!] /local -ti-sum] [ -ti-sum: func [b [block!] s [number!]] [ while [not tail? b] [ set [b s] reduce [next b s + first b] ] s ] -ti-sum b 0 ]
>> ti-sum nums
== 249 turning the recursion into an iteration where the arguments are repeatedly adjusted until arriving at the final answer. HTH! -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [17/47] from: joel:neely:fedex at: 10-Jul-2001 3:08


Ken Anthony wrote:
> Dave, > > Thank you for the geographic analogy... >
Provided we us it appropriately! ;-) In ordinary usage (as in programming) we're more interested in the "places" than the boundaries *between* the "places".
> Your saying days are discontinuous at midnight? ... > > In other words, would July 9th 12:01am belong to July 9th, > but July 9th 12:00am not? >
...
> > ... be like having Canada and the US argue over who owns > > the land under the 49th Parallel. > > In total there's 0.00 acres there to worry about just like > > there's 0.00... seconds to worry about at the `moment of > > midnight'. >
The number zero is *neither* positive nor negative. It is the boundary *between* positive "territory" and negative "territory" on the number line. If we stretch the number line out with a magnifying glass: -1 0 1 2 3 ...: : : : :... ...nnnnnnnnnnzpppppppppppppppppppppppppppppp... ...000000000011111111112222222222... I hope it's clear that the segment marked with "n"s is the negative territory and the "p"s mark positive territory. The z is always the boundary, and however much we zoom in, it never is any wider than the smallest thing we can see, so it has no "width". On the other hand the segment marked with "0"s does have width. It represents the numbers that are at least zero but less than one. Written in decimal, those numbers are 0.000000000... thru 0.999999999... (where the ellipses mean that we never stop... just like this thread ;-) So we can label that "space" with it's lower bound and call it "space 0". Similarly the "1"s label "space 1", the 2 s are "space 2", and so on. This is, of course, not the only way to label spaces. We could put the boundaries in the digits and label each segment by the *nearest* integer, as in -1 0 1 2 3 ...: : : : :... ...nnnnnnnnnnzpppppppppppppppppppppppppppppp... ...000000000011111111112222222222... which we normally call "rounding off". Notice that the same issue still comes up; there's the old standard argument about whether 1.5 should round off to 1.0 or 2.0. In the "good old days" before computers, the standard rule taught in elementary school was that one rounds xxx.5 to the nearest *even* number, so that both 1.5 and 2.5 round to 2.0, while 0.5 rounds to 0.0 and 3.5 rounds to 4.0. This rule looks rather weird to our modern eyes, but had the virtue that it averaged out the round-off error! (In general, half of the rounding went up and half went down, thus cancelling out the accumulated error in a long calculation with randomly-distributed fractions.) OBTW, this also show how "standard practice" changes over time! Speaking of "time", which is how all of this got started, let's do the same magnification on the time-line (at the scale of minutes) and think of how we normally write times. 11:58 11:59 12:00 12:01 12:02 ...: : : : :... ...TTTTTTTTTTTTTTTTTTTTmWWWWWWWWWWWWWWWWWWWW... At the "midnight boundary" between e.g. Tuesday and Wednesday, (shown by the "T" and "W" labels) the ownership of the *moment* of midnight could be argued about all night (;-) but I think we would all agree that the *span* of time which begins at 12:00:00 and includes 12:00:01 through 12:00:59 constitutes the *first* minute of Wednesday. During that entire time, a clock that only shows minutes will read 12:00, leading to the conclusion that (for times, at least) the convention is that the first minute of an hour (as a duration, not a boundary) is labeled 00. -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [18/47] from: kenneth:nwinet at: 10-Jul-2001 6:59


Aw Joel, ya took away my thunder. Great job though... From: "Joel Neely" <[joel--neely--fedex--com]>
> 11:58 11:59 12:00 12:01 12:02 > ...: : : : :...
<<quoted lines omitted: 9>>
> an hour (as a duration, not a boundary) is labeled 00. > -jn-
What I'd intend to do was show (but that you've done better ;-) that given the span of time: Midnight to (Midnight + iota) for any arbitrarily small iota the period belongs to the day following midnight, therefore suggesting that the moment of midnight also belongs to the following day. But you're absolutely right, someone could reverse my argument: (Midnight - iota) to Midnight Then argue any other case (following, preceding, neither, both, contextual) However, it just seems more right to me that 12:00:00.0000000000000000000000000000000000000000000000000000000000000001 which is certainly in the following day be associated with 12:00:00 rather than 11:59:59.999... Neither has the unfortunate side effect that it makes time discontinuous. Both or contextual makes the moment of midnight nondeterministic. I'm still voting for the following day! ;-) Ken. PS: I still round to the next even place, although I admit very seldom these days.

 [19/47] from: agem:crosswinds at: 10-Jul-2001 18:08


RE: [REBOL] Re: On ordinal and cardinal numbers... Hi Joel, its the proto for the Zine i hope? Great! -Volker [joel--neely--fedex--com] wrote:
> Hi, Paul, > Paul Tretter wrote:
<<quoted lines omitted: 13>>
> indirectly. (The standard joke, from the Jargon File, is > recursion n. See recursion. See also tail recursion.
:-)

 [20/47] from: lmecir:mbox:vol:cz at: 7-Jul-2001 12:01


Hi all, is there a chance that Carl gets something more people can agree upon? My idea is to have something like these: 1) SKP function, a zero-based linear skip. The word "linear" means, that it would behave like SKIP, if skipping into the series, which means, that (skp block n) shall produce the same result as (skip block n) for 0<= n <(length? block). For greater offsets it should produce different results. E.g. (skp tail block 1) should produce the same result as (append block 1 result: skip tail block remove back tail block result). Similarly, for negative offsets, if skipping into the block, the result should be the same as the result of SKIP. For lower offsets it should behave differently than SKIP, see below. 2) SKP? function, that will be a counterpart of SKP, i.e. for any block BLOCK the following identity would hold: ((skp? head block) = 0) and for any integer I the following identity would hold: ((skp? skp head block i) = i). 3) a PEK function, that should work (in essence) as follows: pek: function [ [catch] block offset [integer!] /default handler [block!] ] [err] [ if error? err: try [ return first skp :block offset ] [ either default [ return do handler ] [ throw err ] ] ] 4) a POK function, that should work (in essence) as follows: pok: function [ [catch] block offset [integer!] value [any-type!] /default handler [block!] ] [err pos] [ if error? err: try [ pos: skp :block offset return change pos get/any 'value ] [ either default [ return do handler ] [ throw err ] ] ] Regards Ladislav

 [21/47] from: g:santilli:tiscalinet:it at: 7-Jul-2001 15:16


Hello Joel! On 06-Lug-01, you wrote: JN> 1) The issue of whether "the cases in which such code is JN> needed are few" is highly dependent on the application. Yes... it's just that I didn't need that more that a couple times until now. ;-) JN> 2) Having to repeat JN> pick skip foo glarp 1 JN> throughout the code sounds like a great opportunity for JN> typos and other such bugs to creep in. Of course! But you'll need to optimize only that 10%... :) JN> Thanks again for your thought -ful and -provoking comments! The same is valid for me too! Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [22/47] from: joel:neely:fedex at: 6-Jul-2001 23:50


Hi, Ladislav, and all, Ladislav Mecir wrote:
> is there a chance that Carl gets something more people can > agree upon? My idea is to have something like these: >
I'll gladly defer on the detailed specifications to your well- developed (and -demonstrated) patience and attention to detail! At the risk of inconsistency with my own stated views on the unsuitability of English as a specification language... ;-) I think that having 0-based analogs of the following words would be *quite* sufficient: INDEX? SKIP AT PICK POKE Can anyone think of any others that would be critical to performance in manipulating series values?
> ----- Original Message ----- > From: Carl Sassenrath <[carl--rebol--com]> >
...
> > > > Be sure to provide a good name, since that takes more time > > than coding. > >
I'll be quite happy to email these directly to Carl, but would like feedback from the community first. This issue isn't my private property! The best two alternatives I can think of would be: 1) Ryan's suggestion of a /zero refinement to the existing words: index?/zero skip/zero at/zero pick/zero poke/zero PRO: Less global namespace inflation. Learning time of (I have to say it ;-) zero. Mnemonic value. CONS: Possible complexity of adding a refinement to words already "richly endowed" with refinements (but this is purely a judgement call for RT). Trival bit of extra typing (hardly worth notice, but I thought I'd get it out of the way). 2) Parallel words with distinguishing suffix; my minimalist vote would be for: index0? skip0 at0 pick0 poke0 PRO: Mnemonic value. Learning time of essentially (again ;-) zero. Slightly less typing than above option. CON: Adds global words (how big an issue is this?). Digit #"0" and uppercase #"O" look very similar in some typefaces, leading to the possibility of hard-to-detect typos. This could be addressed by using a #"z" suffix instead; that's just a bit stranger-looking to my eyes, but I'm certainly willing to defer to the collective wisdom of the community on this issue. Thus changed, we have indexz? skipz atz pickz pokez IMHO an advantage for either of these naming conventions (vs. e.g., packaging them all in a separate object or using a common prefix) is that the 1-based and 0-based versions would therefore appear together (or very nearby) in alphabetically- sorted lists of words, thus following the "library shelf" principle that similar things should be grouped together to make it easier to find them. print [ random/only [ "feedback" "suggestions" "alternatives" "no flames" ] "welcome! ;-)" ] -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [23/47] from: lmecir:mbox:vol:cz at: 7-Jul-2001 18:09


Hi, 1) I don't know, whether the ATZ and SKIPZ function should differ from each other? 2) If I use one of Joel's naming conventions, I would prefer, that: a) for any block (same? block atz block 0) yields true, it should never yield and error instead b) INDEXZ? shall never yield an error c) for any block and any integer - even for integers greater than the length of the block (equal? i indexz? atz head block i) shall yield TRUE d) PICKZ should behave as follows: pickz: function [ [catch] block offset [integer!] /default handler [block!] ] [err] [ if error? err: try [ return first atz :block offset ] [ either default [ return do handler ] [ throw err ] ] ] d) the POKEZ function, that should work (in essence) as follows: pokez: function [ [catch] block offset [integer!] value [any-type!] /default handler [block!] ] [err pos] [ if error? err: try [ pos: atz :block offset return change pos get/any 'value ] [ either default [ return do handler ] [ throw err ] ] ] 3) The LENGTHZ?, function could be implemented as follows: lengthz?: func [ block ] [ (indexz? tail block) - (indexz? block) ] Regards Ladislav

 [24/47] from: joel:neely:fedex at: 7-Jul-2001 1:44


Jeff Kreis wrote:
> > I think that having 0-based analogs of the following words > > would be *quite* sufficient: INDEX? SKIP AT PICK POKE > > LENGTH? >
I wouldn't see a change here. The block below has a length of ten elements, regardless of which way the positions are labeled IMHO. 1-org 1 2 3 4 5 6 7 8 9 10 block [ a b c d e f g h i j ] 0-org 0 1 2 3 4 5 6 7 8 9 just as there are ten numbers in each of the sets {1 ... 10} and {0 ... 9}
> foo/0 ? >
If you're referring to the naming question, PRO: Less typing than /zero. CON: Still subject to the 0-vs-O issue. Not a big deal either way IMHO. If you mean FOO/0 as a path, then I'd assume that it's still a synonym for PICK FOO 0 and that re-interpreting it as a synonym for PICK0 FOO 0 is not an option at this point. Carl Has Spoken (as is his perfect right and role), so we're only talking about the *addition* of 0-origin capabilities, not a *change* from 1-origin to 0-origin. It is certainly the case that adding 0-origin words/refinements doesn't break any code (as long as we don't reinterpret paths) and that's a legitimate concern. Based on his phrasing "If you really feel that you need a native or two to deal with it..." I assumed that the other option that had been raised (having some sort of global flag that would switch all existing words between 1- and 0-origin behavior) was not acceptable/feasible.
> How does SKIP change? >
After rereading Ladislav's message more carefully, and doing a bit of experimenting for myself, I now think I'd like to remove SKIP/ZERO (or SKIP0) from my proposed list. I would prefer to keep any discussion of how SKIP (etc.) behave at the boundaries as a separate issue from the 0- or 1-origin issue. -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [25/47] from: jeff:rebol at: 7-Jul-2001 8:20


> I think that having 0-based analogs of the following words > would be *quite* sufficient: INDEX? SKIP AT PICK POKE
LENGTH? foo/0 ? How does SKIP change?

 [26/47] from: agem:crosswinds at: 7-Jul-2001 17:23


RE: [REBOL] Re: On ordinal and cardinal numbers... reading Joel he really complains two things: a) stuff is not zero-base b) Joel would be pretty like modulo-arithmetik. i suggest a ring! make ring! 5 could be .. 0 1 2 3 4 5 6 7 8 9 .. or .. -4 -3 -2 -1 0 1 2 3 4 5 .. that means with modulo we could say zeroth: :last while usual c-programming works: while[index < length? block][..] will never touch last! since joel found explaining modulo with a clock works great, how about context clockwise[pick: .. skip: .. ..] ticktack: does bind-to clockwise[ forever[ probe first tick tick: next tick ] ] ? a more complete (complex?) version could really have ring! datatype, which could be a special reference. a: [1 2 3 4] b: make ring! a skip b 24 would work a: make ring! 4 would give us a clock-type counter with no buffer-memory. maybe even a: make clock! [24 60 60 decimal!] there are some uses.. :) Drawback: Joels char-counter would not throw exception on overflow. modulo with subrange just for 0? hm, or 7 as Joel noted. [lmecir--mbox--vol--cz] wrote:
> Hi all, > > is there a chance that Carl gets something more people can agree upon? My > idea is to have something like these: >
;-) Volker --zero is the highest number

 [27/47] from: robbo1mark:aol at: 7-Jul-2001 14:14


Carl / Jeff / Anybody at RT inc. Why not simply have system/options/index-base: Which would be set to 1 if in REBOL 1 = first. But could be set to any number ordinal or cardinal thus allowing whatever base number indexing suits you. I know this would require 'pick etc to be redefined but so perhaps this is less likely to introduced than say a well named base-indexing function(s). Cheers, Mark Dickson In a message dated Fri, 6 Jul 2001 8:27:58 PM Eastern Daylight Time, Carl Sassenrath <[carl--rebol--com]> writes: << First, let me say that as a programmer I do not like one-based math. I've felt that way for more than 20 years. Second, let me ask what is the first paragraph of this email? It is paragraph 1. That's how most of the world sees it. So, there's the rub. Some of you are searching for mathematical purity because you think REBOL is a programming language. REBOL is a language for communication. There are plenty of programming languages out there. Use APL if you want math purity. Use Scheme if you want functional purity, or Prolog if you want logic purity. In REBOL, first = 1 That's the way it is. Sorry if you do not like that. I did not like it. I resisted it for years. I fully understand the singularity it creates in some types of math. That has not been a problem for *most* of the code I write. If you really feel that you need a native or two to deal with it, send me an email with what you want. (If you post it to the list I probably won't see it.) Be sure to provide a good name, since that takes more time than coding. -Carl The guy responsible.

 [28/47] from: jeff:rebol at: 7-Jul-2001 13:14


> > LENGTH? > >
<<quoted lines omitted: 6>>
> just as there are ten numbers in each of the sets {1 > ... 10} and {0 ... 9}
Okay, but the important caveat for everyone to remember is that with 1-based indexing, LENGTH? blk corresponds to the range of positions that can be picked from, changed, etc. However, with zero-based indexing, LENGTH? blk refers to 1+ the range of values pickable, changable. So, for example, the following code behaves differently depending on the base: x: [1 2 3] change at x length? x 0 1-based == [1 2 0] 0-based == [1 2 3 0] This leads to a change of REPEAT as part of a very common REBOL idiom: repeat i length? block [ print [i pick block i ] ] Works for 1-based, but without changing both REPEAT and LENGTH? will break for 0-based (skips the zeroth element and prints NONE on the final iteration).

 [29/47] from: jeff:rebol at: 7-Jul-2001 13:40


> I assumed that the other option that had been raised > (having some sort of global flag that would switch all > existing words between 1- and 0-origin behavior) was not > acceptable/feasible.
A setting verses replicating all the series actions for zero based indexing. If you globally set your base you'll break at least half the scripts you DO, pretty much forever. Some algorithms will be agnostic to the base, but many will not (as Joel Neely has been showing). Programmers shouldn't have to write their code twice for each base that your REBOL might be running under. I tongue and cheek mentioned before about a NEEDS field: REBOL [Title: "Mostly portable" index: 0] ... I've been contemplating that idea: A zero based script DOes a 1 based script (the default) which in turn DOes a zero based script -- etc. Code from the 1 based script calls code from the 0 based script, so REBOL needs to go "Oh, this code over here wants zero, that code wants 1, etc. okay... Now the last 0 based script takes some function that operates on series from a 1 based script that it DOes, binds this into one of its objects containing a number of other functions that operate on series, molds it and stuffs it through a port, which is sucked out on the other side of the Internet by a 1 based script that uses the object to calculate your bank balance ... hmm.. how to keep track of which base belongs to which piece of totally dynamic code... uhhh.. On second thought, replicating all the series actions is sounding much more preferable. (Or changing the base all together and breaking most existing scripts. Weee!) -jeff

 [30/47] from: joel:neely:fedex at: 7-Jul-2001 15:56


Jeff Kreis wrote:
> Okay, but the important caveat for everyone to remember is > that with 1-based indexing, LENGTH? blk corresponds to the > range of positions that can be picked from, changed, etc. > However, with zero-based indexing, LENGTH? blk refers to 1+ > the range of values pickable, changable. >
No offense, but if I didn't already know what we were talking about, I'd have lots of trouble parsing that description. How about saying it this way: One-origin indices range from 1 to LENGTH? blk. Zero-origin indices range from 0 to (LENGTH? blk) - 1. This really is familiar to anyone who's used 0-origin. The 60 minutes in an hour range from 0 to 59. The 24 hours in a standard 24-hour clock range from 0 to 23.
> So, for example, the following code behaves > differently depending on the base: > > x: [1 2 3] > change at x length? x 0 > > 1-based == [1 2 0] > 0-based == [1 2 3 0] >
We're not talking about changing the behavior of AT, but whether we might have a *new* word ATZ (or AT0 or AT/ZERO). Therefore anyone who wanted to change the last element of X could write any of the following change at x length? x 0 change atz x (length? x) - 1 0 change back tail foo
> This leads to a change of REPEAT as part of a very common > REBOL idiom: > > repeat i length? block [ print [i pick block i ] ] > > Works for 1-based, but without changing both REPEAT and > LENGTH? will break for 0-based (skips the zeroth element and > prints NONE on the final iteration). >
The above fragment of code would still work. Anyone who knew (or had learned) enough to write the 0-origin versions could also write it as repeat i length? block [print [i - 1 pickz block i - 1]] Unless, of course, you're joining with me to extend the list of suggested new words to include REPEATZ, so that one could write it as repeatz i length? block [print [i pickz block i]] The only rule is "Be consistent." Don't mix origins unless you know what you're doing. -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [31/47] from: kenneth:nwinet at: 7-Jul-2001 14:10


Hello all, A guiding principle for me is simplicity. Mark's suggestion of a switch is simple but introduces mode which IMHO should almost always be avoided. Of the suggestions put forth by Joel, Ryan and others I would with respect say the following: I emphatically do not like the idea of adding new words that are variations on existing words but the /zero refinement seems most in the spirit of Rebol. Having said that, and even though I think it is a huge mistake for the reasons I will outline (not reiterating the technical points which have been very well represented in this discussion but a touch more on philosophy) I would think it best to remain with the 1-based indexing until such time that Carl changes his mind on the matter. I do a lot of maintenance coding. As a result, although I produce a lot of new code I amazingly find myself reducing the amount of code in a project on any given day. Hardly ever have I seen code, whether I produced it or someone else, that with a little more thought could be made less complicated, cleaner, more elegant, easier to understand, efficient, or... well, you get the idea. There are times when you stop and look at what you've done and you see the very rightness of it. It's a thrill and nobody can take it away from you. Then there's the satifaction of working with some great programmers. When some ask me to review their code I might note that they know there's something not quite right. On those occasions where I can offer a simpler solution I may be giving something that will be carried to others. This isn't always something you can prove or disprove (especially when the very rules of proof are not agreed upon.) But you can sense the rightness. There's a lot of Hype surrounding Rebol which is not unusual when promoting a language, but I want to think about the phrase I've heard that Rebol can take us to the stars. This implies that the language is somewhere on the path that began with stone knives. It also implies that Rebol will not someday be realized to be a dead end as so many others before it have been. For better or worse the design decisions made today guide the very thoughts of the people that will use and produce Rebol code in the future. So is there a rightness about the Rebol language? Obviously so, or there would not be the fuel to ignite the hype. However, there is a dichotomy. What is real and what is artificial? I am of the camp that believes that rigorous proof (as found in mathmatics) is real. I believe that how people feel about doing something because they've always done it that way is artificial. Today, we do not do what we've always done. If we look back at examples, they are embarrassing and silly. Look back 100 to 200 years and they are even more so. Go back a 1000 and things that every child knows today would be incomprehensible to the most educated person. We know the difference between ordinal and cardinal numbers. That has not always been the case. This is a maturing understanding. Most of the numbers we deal with are cardinal and what people think of when we talk about numbers. The ordinal numbers first, second and so on came about as a mapping of position in a series to the quantity to that point. Offsets obviously start from zero (here is always zero away from here - argue against that point at the risk of being revealed...) However, there is no rule anywhere that says what number applies to the position in a series. It is only convention (and simplicity of algorithms) that makes us start with a low positive integer (zero or one) and proceed to assign the next higher integer to the next position. So that leaves us in the uncomfortable position that if we choose zero as the first integer assigned to a position, we've just equated (first = zero.) It's very understandable that some people would be repelled by that. Give it time, in 100 (or 1000) years it will seem natural to you. I have no more to say at this time on this subject. It's been interesting, Ken.

 [32/47] from: jeff:rebol at: 7-Jul-2001 14:28


> The above fragment of code would still work. Anyone who > knew (or had learned) enough to write the 0-origin versions > could also write it as > > repeat i length? block [print [i - 1 pickz block i - 1]] > > Unless, of course, you're joining with me to extend the > list of suggested new words to include REPEATZ
Yes, I was offering up additional changes you'll want to make.
> .. so that one could write it as > > repeatz i length? block [print [i pickz block i]]
.. prints NONE on the last iteration I guess. You sure you don't want LENGTHZ? too? We've already got our bases mixed up.
> The only rule is "Be consistent." Don't mix origins unless > you know what you're doing.
Absolutely. Certainly new people (school kids) learning REBOL will be quite frustrated mixing the two bases going off different peices of example code, for instance, but they'll eventually get it straightened out. -jeff

 [33/47] from: jeff:rebol at: 7-Jul-2001 14:11


> On second thought, replicating all the series actions is > sounding much more preferable. . . .
Also, if performance is of interest (and I think that was the original concern), it's better, performance-wise, to introduce a separate action (PICKZ, PIK, Zick, pickle, whatever) than to use a refinement with an action. Additionally, adding refinements to the existing series actions will impact their present performance, though to what extent I don't really know. With a new batch of actions, the user needs to be mindful of what set of actions they're using and not to mix them, eg: print [ "I am using" pickz which: [1 0] index? next which "base indexing." ] would print: I am using none base indexing. (Which would sort of be true.) -jeff

 [34/47] from: dness:home at: 7-Jul-2001 17:31


Joel Neely wrote:
...
> This really is familiar to anyone who's used 0-origin. The > 60 minutes in an hour range from 0 to 59. The 24 hours in > a standard 24-hour clock range from 0 to 23.
Not to `normal' humans. For most of us a `standard clock' is [12AM, 1AM, ... 11AM, 12PM, 1PM, ..., 11PM] and at TV guide (for reasons that are probably obvious) we used [6,...,29] for a `standard day'. again for `communications' reasons. Note also that astrophysical days start at noon, not midnight, and days in the Jewish calendar, I think, start at Sunset. So even here there's a veritable panoply of 0- and other- origin indexing. My conclusion is that Sassenrath is correct: 0-origin indexing is enormously intellectually more satisfying (J and K, current day derivatives of APL, for example, use it) but for `normal' communication 1- is probably the better choice. And since it;s his playing field, bat and ball, I'm content with the choice. For me, more alternatives wouldn't be better...

 [35/47] from: kenneth:nwinet at: 7-Jul-2001 18:22


Hi Dave, Good thing we're talking about clocks and not ordinals because I've already had my last word on that subject for now ;-)) ----- Original Message ----- From: "David Ness" <[DNess--Home--Com]>
> Joel Neely wrote: > > This really is familiar to anyone who's used 0-origin. The
<<quoted lines omitted: 5>>
> used [6,...,29] for a `standard day'. again for `communications' > reasons.
But we all agree that a day as commonly used (and your point that other uses is certainly valid) is: Midnight < = to < Midnight. So you would agree that the moment of midnight belongs to the day that follows as 12am above suggests? Ken. ps: Either midnight belongs to the day that follows, the day that precedes, neither, both, or is subject to context. I vote for the first! Is it reasonable to vote? I don't think so, but hey I don't want to be different! Oops! Too late... ;-))

 [36/47] from: joel:neely:fedex at: 7-Jul-2001 10:58


Hello, again, Jeff, Jeff Kreis wrote:
> > I assumed that the other option that had been raised > > (having some sort of global flag that would switch all
<<quoted lines omitted: 8>>
> code twice for each base that your REBOL might be running > under.
I don't proposing doing so (either having the flag or writing scripts twice). That said, this kind of global switch setting does occur in other languages. One standard technique for managing the effects is to make the switch read/write, not write-only. A routine that has some reason to twiddle a global switch accepts responsibility for saving the state of the global, doing its own thing, then restoring the state before exiting. It is, of course, much simpler simply to do without features that affect the global state. Just imagine the chaos that could ensue if, for example, we allowed a function to change the current directory, close a file, or modify a global variable... The mind boggles! ;-)
> On second thought, replicating all the series actions is > sounding much more preferable... >
We can certainly agree on that. -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [37/47] from: joel:neely:fedex at: 7-Jul-2001 11:35


Hi, Ken, Admirable (and thought-provoking) summary! Thanks! Ken Anthony wrote:
...
> I believe that how people feel about doing something because > they've always done it that way is artificial. Today, we do
<<quoted lines omitted: 3>>
> every child knows today would be incomprehensible to the > most educated person.
...
> It's very understandable that some people would be repelled > by that. Give it time, in 100 (or 1000) years it will seem > natural to you. >
Your remarks reminded me of another quotation: "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right, and raises at first a formidable outcry in defense of custom. But the tumult soon subsides. Time makes more converts than reason. " --Thomas Paine -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [38/47] from: joel:neely:fedex at: 7-Jul-2001 11:56


Jeff Kreis wrote:
> > .. so that one could write it as > > > > repeatz i length? block [print [i pickz block i]] > > .. prints NONE on the last iteration I guess. >
I'm really puzzled. Why would you guess that? If BLOCK has N elements (for some N) ... then LENGTH? BLOCK evauates to N then REPEATZ I LENGTH? BLOCK is the same as REPEATZ I N then REPEATZ I LENGTH? BLOCK takes I from 0 through N - 1 then [PRINT [I PICKZ BLOCK I]] on the last iteration is the same as [PRINT [N - 1 PICKZ BLOCK N - 1]] which prints the number N - 1, followed by the value of PICKZ BLOCK N - 1, which is the last element of BLOCK. Where did you get NONE?
> You sure you don't want LENGTHZ? too? >
Why? The length of a series does not depend on how we label its positions; whether use the labels 1, 2, 3, 4 or 0, 1, 2, 3 or eenie, meenie, mienie, moe this example still has four labels, therefore a length of four. -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [39/47] from: brett:codeconscious at: 8-Jul-2001 13:06


Quoting Carl,
> If you really feel that you need a native or two to deal with it, send > me an email with what you want. (If you post it to the list I probably > won't see it.) > Be sure to provide a good name, since that takes more time than coding.
Just thought I'd quote it as I believe it means that the language is not going to be rewritten just provide additions for a little more expressivity. I personally don't care what is submitted as long as I have the choice to completely ignore it for writing my scripts and it brings this whole topic rapidly to a close. I've seen this whole discussion and related threads as more entertaining than useful because my preference is to see the language achieve goals through expression rather than revision. I would have loved to have seen the creativity, energy and thoughtfullness so far expended on the zero indexing topic to have been put towards showing people what can be done with the existing language and to encourage further progress on innovative applications of this language. While I've unfortunately not been able to spend as much time as I would like on the Rebol list, I encourage people to share their insights of what can be achieved with this language so that we can build off and learn from each other's knowledge. Let's see some applications people. :) Brett.

 [40/47] from: joel:neely:fedex at: 7-Jul-2001 12:31


[agem--crosswinds--net] wrote:
> reading Joel he really complains two things: >
Me??? Complain??? 8-O
> i suggest a ring! >
Handily done with an object... ring: make object! [ _data: [0 1] _pos: 1 _len: length? _data data: func [b [block!]] [_len: length? _data: copy b skip 0] curr: does [pick _data _pos] next: does [pick _data _pos: _pos // _len + 1] prev: does [pick _data _pos: _pos + _len - 2 // _len + 1] skip: func [n [integer!]] [ pick _data _pos: _pos - 1 + n // _len + _len // _len + 1 ] at: func [n [integer!]] [ pick _data _pos: n - 1 // _len + _len // _len + 1 ] at?: does [_pos] ] which behaves as:
>> nursery-rhyme: make ring [] >> nursery-rhyme/data ["eenie" "meenie" "mienie" "moe"]
== "eenie"
>> loop 5 [prin [nursery-rhyme/next " "]] print ""
meenie mienie moe eenie meenie
>> loop 5 [prin [nursery-rhyme/prev " "]] print ""
eenie moe mienie meenie eenie
>> nursery-rhyme/curr
== "eenie"
>> nursery-rhyme/at?
== 1
>> nursery-rhyme/skip 7
== "moe"
>> nursery-rhyme/at 38
== "meenie"
>> nursery-rhyme/at?
== 2
>> nursery-rhyme/skip -5
== "eenie" The slight awkwardness of using /DATA to configure the content (instead of e.g. MAKE RING [...]) is the price for having LENGTH? _DATA cached instead of being re-evaluated all over the place.
> ;-) Volker > --zero is the highest number >
ROFL!!! -- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [41/47] from: agem:crosswinds at: 8-Jul-2001 7:00


RE: [REBOL] Re: On ordinal and cardinal numbers... [joel--neely--fedex--com] wrote:
> [agem--crosswinds--net] wrote: > > > > reading Joel he really complains two things: > > > > Me??? Complain??? 8-O >
'complain looked so pretty in the dictionary.. no? :(
> > > > i suggest a ring!
<<quoted lines omitted: 40>>
> LENGTH? _DATA cached instead of being re-evaluated all over > the place.
pretty :) but you wanted something native. since we have hash! and list! for special purposes, i thought a datatype! could be more clean than two ways of indexing. a ring! would share the zeroth and the last element. every other index would stay the same. drawback: no range-check. and it would fail with repeat based on 1, hm.. nobody has an idea? :( you used 0-base for simple scaling counting (when categories are with 1-increment instead of 0-9 10-19 ..). which you call a very common job, so some support would make sense. and for modulo-stuff like circular counters, which you apply very clever, but which is a bit harder to read (yes, users shouldn't code, but then they are to stupid to mouse too after all..). something like skip and next for its values would be more friendly. hm, is more friendly with your ready-made example ;-) but modulo-stuff is common also in clocks, foot/yards/miles, some old money-systems, maybe more. so i invented half-joking the clock!, which would be [24 60 60] with clocks, and the miles/yards/foot i don't know yet (metric zone here). we have support for urls and that. nobody want's help for miles? (well, the very common date! is there). since random is so smart to understand series
>> loop 15[random "Hello Jeff"]
== " JoelfeHlf" ;(but what is "feHlf"?!) why not something for crazy-scale-users? make ring! [24 60 60] (but i used that form for the ring-buffer..) BTW could something native like b0: func[index][ index + 1 ] ;base-zero pick block b0 0 help? or to slow/ugly too?
> > > > ;-) Volker > > --zero is the highest number > > > > ROFL!!! >
Thank you. with modulo (0 .. (length? n) - 1) it indexes the same element as length?? :) and for experienced programmers it is far far far more superior to 1 or others as the base, ground, whatever, which makes it highest/greatest/best,.. :) (for deep programming i agree BTW. for simple counting jobs and talking with computers and people iam reluctant )

 [42/47] from: g:santilli:tiscalinet:it at: 8-Jul-2001 11:39


Hello Jeff! On 07-Lug-01, you wrote: JK> Okay, but the important caveat for everyone to remember is JK> that with 1-based indexing, LENGTH? blk corresponds to the [...] Ahem... Jeff... what should then LENGTHZ? [] return? Puzzled, ;-) Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [43/47] from: jeff:rebol at: 8-Jul-2001 9:32


> Ahem... Jeff... what should then LENGTHZ? [] return? > > Puzzled, ;-)
-1 Why should it be intuative? We've disposed of that requirement. (-; repeatz i 0 [print "Below the salt"] repeat i 1 [print "Above the salt"] -jeff

 [44/47] from: larry:ecotope at: 8-Jul-2001 15:59


Hi Joel, Volker Here is a different approach to circular addressing of a REBOL series. The heart of the matter is to be able to skip forward or backward by an arbitray number of steps. Here are two functions which serve that purpose. Rather than copying the the list being operated on, they create and return a series reference with the current index pointing to the desired position. No new series are created, just references. The original series is untouched. Neither of the functions does ANY numeric indexing into the original series. If you want to operate on a copy of the original series just do s: ring-skip n copy b which creates a new series and returns the desired reference. The first function uses iteratation: ring-skip: func [s [series!] n [integer!]] [ either positive? n [ loop n [if tail? s: next s [s: head s]] ][ loop abs n [s: back either head? s [tail s][s]] ] s ] The second uses recursion: ring-skip2: func [s [series!] n [integer!]] [ if n = 0 [return s] either positive? n [ if tail? s: next s [s: head s] ring-skip s n - 1 ][ s: back either head? s [tail s][s] ring-skip s n + 1 ] ] Examples:
>> b: "abcde"
== "abcde"
>> ring-skip b 24
== "e"
>> ring-skip b -1
== "e"
>> s: ring-skip b -1
== "e"
>> ring-skip s -1
== "de"
>> ring-skip b -2
== "de" b: [1 2 3 4 5]
>> b: [1 2 3 4 5]
== [1 2 3 4 5]
>> ring-skip2 b -1
== [5]
>> ring-skip2 b -2
== [4 5]
>> ring-skip2 b 344
== [5] Cheers -Larry

 [45/47] from: joel:neely:fedex at: 8-Jul-2001 19:04


Hi, Larry, Nice variation on the theme! Larry Palmiter wrote:
> Here is a different approach to circular addressing of a REBOL > series. The heart of the matter is to be able to skip forward > or backward by an arbitrary number of steps. Here are two > functions which serve that purpose... > Neither of the functions does ANY numeric indexing into the > original series... >
Ah, you sneaky fellow! ;-)
> The first function uses iteratation: > ring-skip: func [s [series!] n [integer!]] [
<<quoted lines omitted: 16>>
> ] > ]
Absent tail-recursion elimination, I'd always use the iterative version myself (but that's just a personal opinion, and certainly not something I'd force on anyone else). I did have a few observations though... 1) There is a peculiar "singularity" that occurs if the series argument is positioned at the tail, but not at the head.
>> b: "abcde" == "abcde" >> ring-skip b 5 == "abcde" >> c: tail b == "" >> ring-skip c 0 == "" >> ring-skip c 5 == "e" >> ring-skip c -1 == "e"
This could be guarded for at the beginning of either function. 2) Explicitly handing N = 0 is the bottoming-out case for the recursive version. For both recursive and iterative strategies it's also possible to short-cut on a completely empty series, as that case requires no action. There's no significant savings unless one or the other of those cases happens sufficiently often, but it applies to both versions. 3) The last example you gave
>> ring-skip2 b 344
== [5] shows that it's possible to burn lots of cycles with a large enough second argument. Without messing up your policy of no-numeric-indexing ;-) let me mention that there's no need to step forward or backward multiple times around the series. NOTE: I'm assuming here that the series is not totally empty! In your example, the series had a length of 5, so a forward ring-skip of 344 is exactly the same as forward ring-skip of only 4. In addition, a forward or reverse ring-skip of any exact multiple of the series length is the same as no skipping at all. Combining all of these ideas, we could have the following at the beginning of either the iterative or recursive version: if tail? s [s: head s] if any [0 = length? s 0 = n: n // length? s] [return s] after which the function will never make needless "round trips". Of course, implementing idea (3) *requires* bailing out on empty series values to avoid dividing by zero. There may a clever way of rewriting these tests, or perhaps even a suggestion that they're not needed most of the time, but I hope that the benefit of speeding up some cases and removing a few puzzling results are worthy of consideration. Thanks for the interesting ideas! -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

 [46/47] from: larry:ecotope at: 8-Jul-2001 18:45


Hi Joel
> Nice variation on the theme!
Thanks
> Ah, you sneaky fellow! ;-)
;-))
> Absent tail-recursion elimination, I'd always use the iterative > version myself (but that's just a personal opinion, and certainly > not something I'd force on anyone else).
Good point. Actually this recursion is tail recursive, If a function just calls itself there is no problem with the recursion stack, that only happens if there is a delayed expression evaluation, which there is not in this case because the args s and b carry the state. I can illustrate this in more detail if you are interested. But here is a practical example which shows that it is not a problem. It also shows we can generally afford to burn these cycles, REBOL series current index manipulations are quite fast. And I doubt there are many cases where one is interested in a very large skip on a small series. Still.. see below.
>> b: make block! 10000
== []
>> repeat j 10000 [append b j]
== [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 4...
>> t: now/time/precise ring-skip b 10001 now/time/precise - t
== 0:00
>> t: now/time/precise ring-skip2 b 10001 now/time/precise - t
== 0:00:00.06 So the recursion is slightly slower as anticipated. The REBOL internal stack for delayed operations is about 1500 deep, so the example shows that it is does not come into play.
> 1) There is a peculiar "singularity" that occurs if the series > argument is positioned at the tail, but not at the head.
<<quoted lines omitted: 5>>
> >> ring-skip c -1 == "e" > This could be guarded for at the beginning of either function.
Yes, I knew that and originally had some code to deal with it, but I removed it and unfortunately forgot to mention in my post "just don't do that". :-( BTW ring is also not too happy with series at the tail.
>> r: make ring [] >> r/data tail [1 2 3]
** Math Error: Attempt to divide by zero ** Where: skip ** Near: pick _data _pos: _pos -
> 3) The last example you gave > > >> ring-skip2 b 344 > == [5] > > shows that it's possible to burn lots of cycles with a large > enough second argument.
True but see above.
> Combining all of these ideas, we could have the following at the > beginning of either the iterative or recursive version: > > if tail? s [s: head s] > if any [0 = length? s 0 = n: n // length? s] [return s] > > after which the function will never make needless "round trips".
I think I would prefer to just return an empty series for both the case of an actually empty series (i.e., empty? head s returns true) which is already handled and for the case where the current index is at the tail. This signals a problem to the user in an unobtrusive way. The n = 0 case only takes one cycle for the iterative version because LOOP falls through (i.e., the code block does not execute). So I would prefer using just the following as the first line of each of my functions: if any [0 = length? s 0 = n: n // length? s] [return s] Thanks for the suggestions. Cheers -Larry

 [47/47] from: joel:neely:fedex at: 9-Jul-2001 8:11


Larry Palmiter wrote:
> > Absent tail-recursion elimination, I'd always use the > > iterative version myself (but that's just a personal
<<quoted lines omitted: 5>>
> expression evaluation, which there is not in this case > because the args s and b carry the state...
Are you defining "tail recursion", or actually stating that REBOL does tail recursion elimination? (See below...)
> The REBOL internal stack for delayed operations is about > 1500 deep, so the example shows that it is does not come > into play. >
How do you know that? I'm not arguing, just asking -- this is exactly the kind of performance-related information I've been hoping for, and I'd love to find an authoritative source (preferably based on documentation rather than experimentation, but beggars can't be choosers ;-).
> I can illustrate this in more detail if you are interested. >
Yes. I'm extremely interested. I recently tried running some benchmarks which foundered on stack overflow, but I didn't have the time or patience to do the detailed trial and error to find out the depth limit. A quick check with View 1.2 still leaves me puzzled on this point: count-tr: func [target [integer!] /local -count-tr] [ -count-tr: func [current [integer!]] [ either current = target [current] [-count-tr 1 + current] ] -count-tr 0 ]
>> count-tr 10 ;== 10 >> count-tr 100 ;== 100 >> count-tr 1000 ;== 1000 >> count-tr 10000
** Internal Error: Stack overflow ** Near: -count-tr 1 + current Hmmmm... Maybe the nesting of the invocation? count-tr: func [target [integer!] /local -count-tr] [ -count-tr: func [current [integer!]] [ if current = target [return current] -count-tr 1 + current ] -count-tr 0 ]
>> count-tr 10 ;== 10 >> count-tr 100 ;== 100 >> count-tr 1000 ;== 1000 >> count-tr 10000
** Internal Error: Stack overflow ** Near: -count-tr 1 + current Well... Maybe the state needs to be all in the arguments???? count-tr: func [target [integer!] /local -count-tr] [ -count-tr: func [current [integer!] target [integer!]] [ if current = target [return current] -count-tr 1 + current target ] -count-tr 0 target ]
>> count-tr 10 ;== 10 >> count-tr 100 ;== 100 >> count-tr 1000 ;== 1000 >> count-tr 10000
** Internal Error: Stack overflow ** Near: if current = target [return current]
> BTW ring is also not too happy with series at the tail. > > >> r: make ring [] > >> r/data tail [1 2 3] > ** Math Error: Attempt to divide by zero > ** Where: skip > ** Near: pick _data _pos: _pos - >
Thanks for catching that one! With programming, as with music, composing at the keyboard risks dissonance! ;-) Perhaps I'll just redefine RING in terms of the updated RING-SKIP...
> I think I would prefer to just return an empty series for both > the case of an actually empty series (i.e., empty? head s returns > true) which is already handled ... >
Certainly makes sense to me.
> ... and for the case where the current index is at the tail. > This signals a problem to the user in an unobtrusive way. >
I guess tastes differ. Since RING-SKIP TAIL does the wrapping if tail? s [s: head s] for any non-zero number of iterations -- treating the original if tail? s: next s [s: head s] as a refactoring of s: next s if tail? s [s: head s] -- it seemed consistent to do it for zero iterations as well. That way the occurrence of an empty result signals the distinct case of a totally empty argument. But YMMV, of course! -jn- --------------------------------------------------------------- There are two types of science: physics and stamp collecting! -- Sir Arthur Eddington joel-dot-neely-at-fedex-dot-com

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