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