[EMAIL PROTECTED] wrote:
>Galt wrote:
>make-adder: func [x] [func [y] [+ x y]]
>
>Ladislav pointed out that if you use it more than once,
>you must do this:
>make-adder: func [x] [func [y] compose[+ (:x) y]]
>
>Galt again:
>what is the bloody point of having to put in the compose?
>I thought the whole idea here was that contexts were cool,
>and you could use them to have a hidden local variable.
>
>I got this from a Scheme example and there's no extra compose
>needed there.
>
>I am guessing that the problem is that there is only one
>copy of the block [+ x y] and that it has a context, whatever
>that is, and that it can only have one context, and that one
>gets changed everytime you run make-adder again with a new
>parameter value for x. So running make-adder a 2nd time
>messes up the value hidden in the context of the first?
You are so close ;)
Blocks do not themselves have context - they just exist in
whatever context they are defined in. In this case, it is
the context of the function assigned to the word make-adder
that matters here.
You are correct that this context is reused. Functions use
a single context object for their variables which is reused
with every call. This provides a major speedup to REBOL, an
advantage to the 2.x versions. New context objects are made
generated for recursive calls to the same function, though,
part of the reason that recursion is rather limited now.
>with the original simple method, you get this:
> >> source add6
>add6: func [y][+ x y]
>
>with Ladislav's method, you get this:
> >> source add6
>add6: func [y][+ 6 y]
>
>which is a nice demonstration.
>But it's mechanism doesn't depend on context at all any more.
>The function is really returning 6 not X with context.
>6 is 6 in any context, so big whoop?
It depends on context at the time of function creation.
Resolving the context issues when the context is still
active is generally a good idea, both in Scheme and in
REBOL. There are weird drawbacks in REBOL to accessing
function contexts (reuse) and use contexts (not GC safe)
out of context. In Scheme, such behavior leads to extra
memory related to uncollected contexts bloating memory
requirements.
In general, the only safe way to refer to contexts from
the outside is with object contexts, and then only when
the object is referenced so it won't be collected by the
garbage collector (recycle).
>Did this used to work in an older rebol without compose?
No.
>I note that this works, too, silly as it is:
> >> make-adder: func [x] [func [y] reduce['+ x 'y]]
It's not silly, it's faster. I'd use this to be safe:
>> make-adder: func [x] [func [y] reduce ['add :x 'y]]
because + is normally infix, not prefix, and because x
might be a function or paren, making normal evaluation
problematic.
>And this failed to work, which surprised me, so I guess
>I still don't get it yet:
> >> z: [+ x y]
> >> make-adder: func [x] [func [y] bind copy z 'x]
>I was hoping that I could make a new copy of the z block
>each time make-adder was called, and then make x take on
>a different value in the context of each copy.
That's equivalent to your first example, but using
more memory. Here's a few tips to help you get it:
- The context is associated with the function, not
the block.
- Both reduce and compose create new blocks.
- Bind copy can be done as bind/copy, and faster.
- Function contexts are reused, if possible.
- No contexts, including function, use and object
are safe from the garbage collector unless they
are referenced in some direct way. Only contexts
from objects and non-recursive functions can be
referenced in any persistent way, and then only
as long as their associated function or object is
referenced. Recursive function and use contexts
are not safe to refer to from the outside.
- Overall, you should resolve any context references
as soon as you can, both for speed and safety. It
is perfectly all right to replace a word that is
supposed to refer to a constant value with that
literal value, and the resulting code will be a
little faster to execute.
- Remember that REBOL is (currently) an interpreted
language, not compiled. This means that you can't
rely on an optimizer to clean up your critical
code - you have to do it yourself.
>Maybe somebody could show me how to do it using contexts?
All the examples you've shown, and all of REBOL as
well, uses contexts. The compose and reduce examples
just resolve those context references while they are
safe to do so.
You can't translate all of Scheme into REBOL directly.
In particular, the code that would be obscure or silly
to do in a non-compiled Scheme needs a little work :)
Brian Hawley