Mailing List Archive: 49091 messages

## [REBOL] Re: Why does 'reverse returns the tail of the block?

### From: joel:neely:fedex at: 12-Nov-2002 7:04

```
Hi, Andrew,

Another wild guess below...

Andrew Martin wrote:
> Jan wrote:
> > > worst of all 'reverse, which returns empty block.
>
> Gabriele wrote:
> > I  don't  know  why REVERSE returns the tail of the block.
> > You can use HEAD REVERSE in expressions,...
>
> I suspect that 'reverse returns the 'tail of the block, because
> to return the 'head of the block could be wrong, if one is
> 'reverse-ing only part of a block?
>

But those aren't the only two options!  IMHO the more intuitive
thing would be to return a block reference positioned at the
same place as the beginning of the reversed sequence (see below
for example).  I'm inclined to wonder whether the resulting
value is merely an artifact of the way REVERSE is implemented,
rather than being carefully chosen for some strategic purpose.

> For example:
>
> >> reverse next x: [1 2 3 4 5]
> == []
> >> x
> == [1 5 4 3 2]
>

following *H*Y*P*O*T*H*E*T*I*C*A*L* case

>> reverse next x: [1 2 3 4 5]
== [5 4 3 2]
>> x
== [1 5 4 3 2]

As it is, we can get roughly the equivalent behavior only at the
cost of some extra typing ...

>> reverse y: next x: [1 2 3 4 5]
== []
>> y
== [5 4 3 2]

... to preserve the position of the series (sub-) reference.

REBOL seems in general to follow the principle of returning
results that are most likely to be useful in a larger expression
(e.g. INSERT returns a reference *after* the inserted content,
making it easy to "chain" insertions into a single expression).
That principle is broken here IMHO as every use I can recall
making of REVERSE falls into one of two categories:

1)  Imperative - purely for effect, in which case I don't *care*
how the resulting value is positioned, or

2)  In-line - needing to perform some additional manipulation
on the result, in which case I *always* have to write the
equivalent of

to get back to the beginning of the REVERSEd content.

I'd much rather have REVERSE return a preserved position.

> Though I'm not sure why one would want to only reverse part of
> a block (or series)?
>

Most (all?) operations on series values respect the current
position within the underlying sequence.  Consistency with that
rule is A Good Thing IMHO.  A specific example of how this could
be used is the "line breaking" problem:  given an ordered
collection of values and a position within the collection, bring
the value at that position to the "front of the line" without
disturbing the relative order of the rest of the values in the
collection.

An obvious approach is to insert the designated value (i.e. the
value at the designated position) into the front of the line,
and remove it from its previous place.  This is easy to write:

breakline-ins-rem: func [
s [series!] p [integer!]
][
head remove at insert s pick s p p
]

It behaves as specified ...

>> breakline-ins-rem [1 2 3 4 5 6 7 8 9] 4
== [4 1 2 3 5 6 7 8 9]

... but we know that INSERTing and REMOVEing (in blocks with
many values following the point of action) can be expensive.

A subtler approach can be designed as follows:

- REVERSEing a subseries at the beginning will put the desired
element at the head of the line, but will mess up the relative
order of the values that were before it:

>> head reverse/part [1 2 3 4 5 6 7 8 9] 4
== [4 3 2 1 5 6 7 8 9]

- We can prevent that by REVERSEingthe *preceding* values first,
and then REVERSEing the entire leading subseries:

>> head reverse/part [1 2 3 4 5 6 7 8 9] 3
== [3 2 1 4 5 6 7 8 9]
>> head reverse/part [3 2 1 4 5 6 7 8 9] 4
== [4 1 2 3 5 6 7 8 9]

This gives us another design ...

breakline-rev-rev: func [
s [series!] p [integer!]
][
]

... which only manipulates the part of the series that actually
needs to change!  This latter version can be *much* faster,
depending on the length of the series and how close the desired
position is to the front.

-jn-

--
; Joel Neely                             joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
```