###What happens to the list after we assign an element to Sequence[]
The answers given so far already contain most of the pieces needed to explain this behavior, but I decided to still add this answer.
This topic has been discussed many times in the past, although not on this site. Here is one such discussion, where I also contributed an answer. I will take my answer from there, and adopt it to this case.
Consider your example:
xx = Range[5]; xx[[1]] = Sequence[]; xx
Now, let us see what is in xx
:
?xx
Global`xx
xx={Sequence[],2,3,4,5}
We see that the first element is still there.
###Some reasoning behind this behavior
We don't really change the size of a list (as stored in OwnValues
etc) by assigning Sequence[]
to some of its elements - Sequence[]
is just as good an element as anything else.
The important part to realize is that all the Sequence[]
magic happens at
evaluation stage - the size of an evaluated list becomes effectively
smaller as a result of evaluation (during which Sequence
-s inside heads
without SequenceHold
or HoldAllComplete
attribute are spliced).
This seems entirely consistent, given that lists are internally
implemented as arrays and then to really change the size of a list as it is
stored, we would generally need O(n) operations where n is the size of the
list. OTOH, operations like Part
and assignments should not be concerned with anything else than just assigning parts of expressions, and such list
rearrangements should be beyond their scope IMO.
###Back to the example
Returning to your example, all subsequent assignments simply re-assign
Sequence[]
to the first element. Since the list is not evaluated during the part assignment, Sequence
splicing does not happen.
Here is one way to get the elements removed, which would further clarify things.
xx = Range[5];
xx[[1]] = Sequence[];
xx = xx
xx[[1]] = Sequence[];
xx = xx
xx[[1]] = Sequence[];
xx = xx
(*
{2, 3, 4, 5}
{3, 4, 5}
{4, 5}
*)
In this case, the code does what we need - removes the first element each time. The key part here is the assignment xx = xx
. In this case it is non-trivial, because we do evaluate xx
on the r.h.s. during the assignment, the Sequence
splicing proceeds as it should, and then we assigned the result (which no longer contains the original first element, and is one element smaller now), to the same variable.
###Summary
What you have observed is a result of an interplay between evaluation and the way part assignments are performed. Here are some things to keep in mind regarding this:
- Part assignments fundamentally can not remove elements from an expression stored in a variable.
- Assigning
Sequence[]
(or Nothing
, for that matter) to a part of an expression will not remove that part, but rather put there Sequence[]
or Nothing
. Indeed, this seems to be the only sensible behavior.
- Shrinking of expressions containing
Sequence[]
is an evaluation-time effect, while expressions stored in variables are kept unevaluated, also during part assignments.
These points together explain your observation. In fact, this is just one reason to avoid using Sequence
as an element-removing device, when possible. There are other options available for that. If you really do want to change your expression (stored in a symbol) via Sequence
part assignment, one way to do that is to reassign the expression to the variable, using var = var
idiom, allowing it to evaluate.