Hello, all,

I found the following little explorations instructive while thinking
about words and contexts.  I hope they are of interest/value to
someone else.


Let's make a block of words:

    >> bow: []
    == []
    >> repeat i 5 [append bow i]
    == [1 2 3 4 5]

Woops!  That gave me a block of integers, not a block of words.
Besides which, I hate using variables unless necessary.

I can get rid of the variable BOW (since REBOL is a very literal
language) like this:

    >> repeat i 5 [append [] i]
    == [1 2 3 4 5]

Now let's get a block of words instead of a block of integers:

    >> repeat i 5 [append [] [i]]
    == [i i i i i]

But is that a block of five homographs (distinct words whose names
are all spelled the same), or is it a block with five references
to the same word?

    >> reduce repeat i 5 [append [] [i]]
    == [6 6 6 6 6]

It's five references to the same word.


        Thought 1:  REPEAT creates a context when executed.
                    Within the block that is evaluated REPEATedly,
        the word that is the first argument to REPEAT is in that
        new context.  (* Not considering the use of nested words
        that also create contexts, e.g. USE, etc...)


But what if I *really* want a block of homographs?  Hmmmm.
Let's try sticking another context-creating word in there.

    >> reduce repeat i 5 [use [.i] [.i: i append [] [.i]]]
    == [5 5 5 5 5]

Again we get five references to the same word!


        Thought 2:  USE creates a context when executed.  When
                    word(s) in the first argument appear in the
        second argument, they are words in that context.  It
        appears that there's a side-effect of "remembering" that
        fact so that subsequent USEs of the same block are still
        involved with that context.


Hmmm.  If I give USE a fresh second block every time, then I can
avoid the side-effect.

    >> reduce repeat i 5 [use [.i] copy [.i: i append [] [.i]]]
    == [5 5 5 5 5]

Duh!  A simple COPY doesn't get to the .I that's in an additional
"layer" of block nesting.

    >> reduce repeat i 5 [use [.i] copy/deep [.i: i append [] [.i]]]
    == [5]

Double-duh!  Now there's a fresh empty block for every evaluation
of USE.  Sigh...  The only way I can think of to get around that is
to re-introduce a word to serve as a "variable".

    >> b: []
    == []
    >> reduce repeat i 5 [use [.i] copy/deep [.i: i append b [.i]]]
    == [1 2 3 4 5]

Aha!  It looks like I (finally!) have five homographs!  I'd really
like to look at them, though...

    >> repeat i 5 [use [.i] copy/deep [.i: i append b [.i]]]
    == [.i .i .i .i .i .i .i .i .i .i]

Rats!  That's why I hate using "variables".  Side-effects accumulate!
While I'm at it, I'll keep the result this time so that I can look
at the "raw" block and also REDUCE it:

    >> b: []
    == []
    >> c: repeat i 5 [use [.i] copy/deep [.i: i append b [.i]]]
    == [.i .i .i .i .i]
    >> reduce c
    == [1 2 3 4 5]

Yes!  Five homographs!  Just what I wanted!


        Thought 3:  COPY/DEEP is a way to avoid the side-effect
                    that USE has on its second block.  However,
        I have to remember that COPY/DEEP also blows away any
        side-effects on literal values!


I wonder -- is there any way to get homographs without losing the
ability to have literal values?  How else can we create contexts?
How about with a function?

    >> apparg: func [b x] [append b [x]]
    >> c: repeat i 5 [apparg [] i]
    == [x x x x x]
    >> reduce c
    == [5 5 5 5 5]

Hmmmph!  (Insert appropriate numbers of "duh" ;-)  I'm back to
getting five occurrences of the same word.  Oh yeah...


        Thought 4:  The context of a function is persistent.
                    Subsequent uses of the function are using
        the same context.  This isn't like ___ (insert name of
        commonly-used language here) which creates a new frame
        or environment for each invocation of a function.


I suspect that this might be a performance choice.  Create the
context when the function is defined, and keep it around to avoid
repeating that work every time the function is evaluated.

Errrk?  What about recursion?

    >> rapparg: func [b i x] [
    [    either i > x [b] [rapparg append b [i] i + 1 x]
    [    ]
    >> c: rapparg [] 1 5
    == [i i i i i]
    >> reduce c
    == [1 1 1 1 1]


Well, it *looks like* I is getting saved and restored for the
recursive calls, but let's make sure (by using some fairly
gnarly-looking before-and-after tracing):

    >> rapparg: func [b i x /local r] [
    [    print b
    [    r: either i > x [b] [rapparg append b [i] i + 1 x]
    [    print r
    [    r
    [    ]
    >> c: rapparg [] 1 5

    2
    3 3
    4 4 4
    5 5 5 5
    6 6 6 6 6
    6 6 6 6 6
    5 5 5 5 5
    4 4 4 4 4
    3 3 3 3 3
    2 2 2 2 2
    1 1 1 1 1
    == [i i i i i]
    >> reduce c
    == [1 1 1 1 1]

Yup!  The argument block is accumulating a bunch of references
to the same word (an argument) whose value is being saved and
restored to make the recursive call behave like one would
expect it to.


        Thought 5:  I suspect that means that there's a time
                    penalty for using recursion (compared to
        repeatedly calling the same function within an iteration)
        but that benchmark will have to wait for another day.


Wait a minute!  My attention is wandering!  I wanted to make a
block of homographs.  How else can I make new contexts?   Whoa!
I can make a new function everytime I iterate!

    >> c: repeat i 5 [do func [b x] [append b [x]] [] i]
    == [x x x x x]
    >> reduce c
    == [1 2 3 4 5]

Yeehah!  Now I get a fresh context (and therefore a fresh word)
every time.


        Thought 6:  FUNC appears *not* to have the side-effect
                    of altering its second block (in the way
        that USE does).  Subsequent uses of FUNC ... ... really
        get me a new context for each evaluation.


Of course, being stubborn as well as simple-minded, I can't help
but think about the idea of USE inside the body of a function.
Since USE seems to have a side-effect on its second (literal)
argument, I would expect to get the same word over and over.
Let's try it...

    >> appuse: func [b x] [use [.x] [.x: x append b [.x]]]
    >> c: repeat i 5 [appuse [] i]
    == [.x .x .x .x .x]
    >> reduce c
    == [1 2 3 4 5]

Wot???  I got five homographs! Does USE inside a function body
behave differently than USE at the console level?

    >> repfun: func [b x] [repeat i x [use [.x] [.x: i append b [.x]]]]
    >> c: repfun [] 5
    == [.x .x .x .x .x]
    >> reduce c
    == [1 2 3 4 5]

It does!  We're back to five homographs, even though the body of REPFUN
is essentially the same as the unsucessful attempt from the console
prompt earlier (except for using an argument instead of a literal as
the object of the APPEND).


        Thought 7:  There's more going on here than meets the eye.
                    I need another cup of coffee.


As usual, feedback/comments/corrections/coffee are welcome!  ;-)

-jn-

-- 
joelDOTneelyATfedexDOTcom
-- 
To unsubscribe from this list, please send an email to
[EMAIL PROTECTED] with "unsubscribe" in the 
subject, without the quotes.

Reply via email to