[REBOL] Context Stuff Re:
From: bhandley:zip:au at: 1-Aug-2000 11:13
> Ok, I have been trying to understand this context stuff.
> I created a function and have a "word" within a while function
> embedded within. The problem is that the function does everything I want
> the first time.
A lot of people would like their code to work first time ;)
> However the "word" within the while function continues to
> hold the last value. I can do a source on the function and see the last
> value within. How can I have the function return the string value to
> nothing at the end of exection.
Since I tripped over this myself, and others helped me, it's my turn.
my-func1: func  [
; blk-in-function-definition will refer directly to a block that is
stored as part of the function definition
append blk-in-function-definition "x"
my-func2: func  [
; new-blk-each-call will refer to a block that is created each time the
function is evaluated
new-blk-each-call: make block! 1 ; Creates a fresh block another way is
use copy 
append new-blk-each-call "x"
I've attached a message by Brian Hawley showing how this behaviour can be
put to good use.
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
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]]
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.