Hi Brett!
While you're reassembling, think of the advantages that this
trick can give you. This kind of assignment can be useful for
implementing what the C world calls static local variables.
You can set a word to a literal string value, then append to
that string to create a string accumulator. This allows you
to build a string incrementally.
You can set a word to a literal block and store values in it.
This allows you to use a function like a Scheme closure, a
function with values bundled in it, like OOP in reverse. This
technique allows OOP-like programming with better control of
your data because it is hidden inside the function. Look at
http://www.bigfoot.com/~brian.hawley/rebol/require.r for an
example of how this technique can make for bulletproof code.
The most fun with this technique comes when you use compose
to create your code blocks. For example, consider this:
f: func [key] [
table: make hash! [a "a" b "b"] table/:key
]
Trivial, true, but imagine that pattern with a much larger
hash table, or a large binary value, or a dozen charsets for
a parse process. You can't directly represent those values
as literals - they get recreated every time. Do that in a
function and the function gets really slow. But do this:
f: func [key] compose [
table: (make hash! [a "a" b "b"]) table/:key
]
and the hash table is only created once, right before the
function is created. All calls to f then reference the now
literal hash table, making for a very fast, memory efficient
function.
If you can use literal hash tables in a function, you can do
one of the coolest tricks from the functional-language world,
memoization. When you memoize a function, it remembers the
results of the calls to the function, so that later calls of
that value don't have to recalculate the result. You can even
do this from the outside with a separate function, although
REBOL's flexible args make the general case of that rather
tricky (I'll work on it). Here's a one-arg memoize function:
memoize: func ["One-arg memoize, kinda weak :(" 'f [word!]] [
set f func [x /local f saved res] compose [
f: (get f) saved: (make hash! [])
either res: select saved :x [first res] [
res: f x
append saved reduce [:x reduce [res]]
res
]
]
]
I know, it looks awkward, but this can speed up functions
that have to go through even worse trouble to calculate
their values in the first place. It also helps with those
that use deep self-recursion to calculate their values, as
REBOL's stack space is quite limited.
Fun stuff?
Brian Hawley
[EMAIL PROTECTED] wrote:
><picks jaw off ground/>
>
>Thanks Ingo,
>I'll just have to go away and reassemble some brain patterns...
>
>Brett.
>
>----- Original Message -----
>From: <[EMAIL PROTECTED]>
>To: <[EMAIL PROTECTED]>
>Sent: Sunday, July 02, 2000 12:48 AM
>Subject: [REBOL] Parser seems to have bug - different results on multiple
>calls. Re:(4)
>
>
> > Hi Brett,
> >
> > maybe this little func 'll show you what's happening ...
> >
> > test: func [] [
> > s1: ""
> > s2: copy ""
> > append s1 "Hi, I'm changed"
> > append s2 "I'm not ..."
> > source test
> > ]
> >
> > >> test
> > test: func [][
> > s1: "Hi, I'm changed"
> > s2: copy ""
> > append s1 "Hi, I'm changed"
> > append s2 "I'm not ..."
> > source test
> > ]
> >
> > You see, s1 has literally been changed in the source-code,
> > s2 has not. (It's one of the Rebol traps everyone has to
> > fall into once.)