Short summary:
1) Series literals are just initializers. Once you set something to
refer to them, they are subject to modification.
2) Applying 'reduce to a string returns the same string.
3) Applying 'reduce to a block returns a different block.
[EMAIL PROTECTED] wrote:
>
...
> I disagree with your analysis of 'reduce. See the following console
> stuff:
>
> f1: func[/locala][a: "" insert a 1 a]
> f2: func[/local a][a: [none] insert a 1 a ]
> f3: func[/local a][a: reduce "" insert a 1 a]
> f4: func[/local a][a: reduce [none] insert a 1 a]
>
> Now check the sources after an execution:
>
> >> f1 source f1
> f1: func [/locala][a: "1" insert a 1 a]
> >> f2 source f2
> f2: func [/local a][a: [1 none] insert a 1 a]
> >> f3 source f3
> f3: func [/local a][a: reduce "1" insert a 1 a]
> >> f4 source f4
> f4: func [/local a][a: reduce [none] insert a 1 a]
> >>
>
> I corrected a typo in the above. Originally I had local/, an invalid path.
>
> Why does [none] act the same as "" in the first two examples, but
> differently in the second two examples?
>
Both f1 and f2 contain literal series values. IMHO, the best way to
think of a literal series (block or string) is as the INITIAL value
of a series (block or string) created at translation time (from text
to internal representation). However, if you set a word (local or
global) to refer to that series, and then subsequently use a function
on that word which produces a side-effect, you will be modifying the
actual series. Therefore, it will no longer have the value with
which it was initialized (in the original text).
The first two examples work this way. Prior to the first execution,
the body of f2 can be thought of as:
{{block! 1 *}}
|
V
<< a: * insert a 1 a >>
|
V
{{block! 1 *}}
|
V
<< none >>
During execution, the local word 'a is set to refer to the block given
in the second element of the body
{{block! 1 *}}
|
V
<< a: * insert a 1 a >>
|
V
a -------------> {{block! 1 *}}
|
V
<< none >>
The 'insert modifies the block referred to by a (which is still referred
to by the second element of f2's body).
{{block! 1 *}}
|
V
<< a: * insert a 1 a >>
|
V
a -------------> {{block! 1 *}}
|
V
<< 1 none >>
After this, pretty-printing the body of f2 (using 'source) produces just
what the above picture indicates:
[a: [1 none] insert a 1 a]
The same thing happens with f1, except that the second element of the
body
of f1 is a string, so the state of f1's body right before f1 exits is
{{block! 1 *}}
|
V
<< a: * insert a 1 a >>
|
V
a -------------> {{string! 1 *}}
|
V
<< #"1" >>
The situation with f3 and f4 is a bit different (and depends on what
seems to be an undocumented feature of 'reduce).
It appears that 'reduce is clever enough to know that evaluating a
string value simply returns that same value. Therefore 'reduce just
gives back a reference to its argument if that argument is a string.
This is demonstrated in the console transcript:
>> a: ""
== ""
>> reduce a
== ""
>> same? a reduce a
== true
Therefore, f3 is just an obscure variation on f1. The local variable
a is set to the result returned by 'reduce, which is just another
reference to the third element of the body.
Finally, understanding f4 DOES require knowing that 'reduce returns
a new block.
>
> I'm not sure 'reduce "creates a new block.
>
It does if its argument is a block. Consider this
>> a: [ "" ]
== [""]
>> reduce a
== [""]
>> same? a reduce a
== false
I returns a block, and that block is NOT the same as the argument
block. Therefore, the body of f4 looks something like
{{block! 1 *}}
|
V
<< a: reduce * insert a 1 a >>
|
V
{{block! 1 *}}
|
V
<< none >>
and the result of evaluating f4 up to (but not including) the
'insert is
{{block! 1 *}}
|
V
<< a: reduce * insert a 1 a >>
|
V
{{block! 1 *}}
|
V
<< none >>
a -> {{block! 1 *}}
|
V
<< none >>
Because the local variable a refers to a different series than the
one at the third element of f4's body, modifying that series doesn't
have a side-effect on f4's body. After the 'insert, we have
{{block! 1 *}}
|
V
<< a: reduce * insert a 1 a >>
|
V
{{block! 1 *}}
|
V
<< none >>
a -> {{block! 1 *}}
|
V
<< 1 none >>
Therefore, after f4 has been used once, we can look at its body via
'source and the block literal initialized as [none] is unchanged.
> ? 'reduce doesn't say that. [that it returns a different block]
It appears to me that 'help is more of a memory jogger than a full
explanation. And we've seen cases where even the full documentation
doesn't cover every subtlety of REBOL. (Maybe that's why we'll all
run out and buy the book! ;-)
>
> I still think this is a bug. If not, it's so odd that an extensive
> documentation should be devoted to it.
>
It isn't a bug, IMHO. It is a subtle consequence of how REBOL handles
series values. I agree with you that the standard documentation needs
beefing up (although I'm sure the folks at REBOL.com have their hands
full with the book and getting 2.2 up on all the remaining platforms).
That's why I invested the effort in writing up the "essay" on series
values that I posted to this list. I really believe that the over-
simplification of descriptions and terminology is at the root of many
of the "problem cases" we've had discussed on this mailing list.
I hope that reading it helps someone else as much as writing has helped
me.
-jn-