Trying to compose a block out of global and local bindings
[1/12] from: princepawn::lycos::com at: 7-Sep-2000 13:02
>> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n print reform reduce
b] ]
>> form
== ["hi" name "welcome back"]
>> name
== "bob"
>> letter2 form
hi bob welcome back
hi bob welcome back
... the only problem is I was hoping that the loop values in letter2 would take precedence
over the globally bound value of name and allow me to create a form letter of sorts.
Could anyone help with this please?
[2/12] from: ssayer:acuson at: 7-Sep-2000 18:02
I'll point out quickly that what you're trying to do is generally
considered a bad programming practice, i.e. referencing a variable
internal to a function from its argument. A caller shouldn't need to know
about and shouldn't really have direct access to variables local to a
function.
I will however provide an example of how to do what I think you're trying
to do and recommend that you rethink your approach in any case because
this is almost as bad but I think it demonstrates that your problem was
perhaps not one as much of scope but more of tokenization:
>> letter2: func [b][foreach n ["sally" "sue"][print replace (copy b) 'name n]]
>> greeting: ["hi" name "welcome back"]
== ["hi" name "welcome back"]
>> {I prefer not to overwrite REBOL words, like "form" from your example}
== {I prefer not to overwrite REBOL words, like "form" from your example}
>> name: "bob"
== "bob"
>> letter2 greeting
hi sally welcome back
hi sue welcome back
>>
FWIW,
<SS>
On Thu, 7 Sep 2000 [princepawn--lycos--com] wrote:
[3/12] from: alex:pini:mclink:it at: 8-Sep-2000 0:05
>- Open Your Mind -<
Quoting from [princepawn--lycos--com's] message (07-Sep-00 22:02:43).
p>>> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n print reform reduce
b] ]
p>
p>>> form
p> == ["hi" name "welcome back"]
p>
p>>> name
p> == "bob"
p>
p>>> letter2 form
p> hi bob welcome back
p> hi bob welcome back
p>
p> ... the only problem is I was hoping that the loop values in letter2 would take precedence
over the globally bound value of name and allow me to create a form letter of sorts.
p>
p> Could anyone help with this please?
letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n print bind b 'name]
]
Note that I don't really believe I've understood this myself. :-9
Also note you've just redefined the *form* native function...
Alessandro Pini ([alex--pini--mclink--it])
I'm just the... *shadow* of my former self.
(Morden)
[4/12] from: alex:pini:mclink:it at: 8-Sep-2000 0:28
>- Open Your Mind -<
Quoting from my message (08-Sep-00 00:05:00).
a> Note that I don't really believe I've understood this myself. :-9
... Note that the ":-9" is due to a malfunctioning shift-key, I'm not that horny about
being bound. :-)
Alessandro Pini ([alex--pini--mclink--it])
For sex.
"No! Oh... er, that, too!" (J. Dax & Quark)
[5/12] from: lmecir:geocities at: 8-Sep-2000 0:38
Hi,
try this:
letter2: func [b] [foreach name ["sally" "sue"][print bind/copy b
'name]]
form: ["hi" name "welcome back"]
letter2 form
Regards
Ladislav
> >> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n print
reform reduce b] ]
> >> form
> == ["hi" name "welcome back"]
<<quoted lines omitted: 4>>
> hi bob welcome back
> ... the only problem is I was hoping that the loop values in letter2 would
take precedence over the globally bound value of name and allow me to create
a form letter of sorts.
[6/12] from: rebol:techscribe at: 7-Sep-2000 23:50
Hi princepawn,
pretty much everything has already been said.
(1) I just happened to notice that you redefine form (was pointed out) AND
use reform:
>> source reform
reform: func [
"Forms a reduced block and returns a string."
value "Value to reduce and form"
][
form reduce value
]
You see that reform uses form.
So at the time you evaluate reform, if we explicitly replace form by the
value you assigned to it, then we get:
reform: func [
"Forms a reduced block and returns a string."
value "Value to reduce and form"
][
["hi" name "welcome back"] reduce value
]
reform no long performs a FORM on its argument!
Since the result of a function is the value its body evaluates to (unless
you use return at some point) in this case reform will simply return its
reduced argument. Which leads me to ...
... (2) you use
[ name: n print reform reduce b]
... reform reduce ...
Recall the implementation of reform. The reform function performs a reduce
on its argument, and therefore your explicit use of reduce is redundant.
The whole difference between reform and form is that reform first REDUCEs
its argument before it FORMs it. But you are using print ...
... and (3) print reduces its argument quite on its own anyway. The print
function accepts a block as its argument and is not limited to an argument
of type string!. Therefore you do not need to reduce or reform b. Passing b
to print alone will work just fine, provided the name in the b block is
bound to the context of foreach. Which leads me to ...
... A final word. What name evaluates to depends on the context in which it
is defined. There are two instances of name involved in your function. One
instance of name is bound to the global context:
["hi" name "welcome back"]
where name is associated with the string "Bob".
The other name is local to the function. When you set name to the value of
n, then you are setting the instance of name that is bound to the local
function to that value (obviously). The argument you pass to reduce,
however, is the block that was constructed in the global context, and
therefore the name instance it contains is the name bound to the global
context.
Actually you do not want the second name instance to be local to the
letter2 function. You want the second name instance to be bound to the
foreach (native!) function.
So, you could say
letter2: func [b] [
foreach name ["Sue" "Sally"] [
print bind b 'name
]
]
Here BIND directs REBOL to associate all words contained in 'b with the
closest
context that contains the symbol name. Because
1. the context in which the BIND expression is being used is the block
passed to foreach, and
2.
a) because the first argument passed to foreach (foreach name ...) is an
instance of the word name
b) there therefore now exists an instance of the word name that is bound to
foreach's context,
3. ==> therefore
a) REBOL will identify foreach's context as the "closest" context in which
'name occurs. This is the context to which all words in the block b are now
being bound, provided they are defined in foreach's context.
b) Because of 3.a) the symbol name in the block b will be bound to the
foreach context. (If the block b contained other words and some or all of
these other words were also defined in the foreach context, then all these
words would be bound to the foreach context as well. Words that are not
defined in the foreach context remain bound to whichever context they
originated in, when the block b was formed, or they remain unset!, if they
were never set to a value to begin with).
RESULT:
>> name: "Bob"
== "Bob"
>> message: ["hi" name "welcome back"]
== ["hi" name "welcome back"]
>> letter2: func [b] [
[ foreach name ["Sue" "Sally"] [
[ print bind b 'name
[ ]
[ ]
>> letter2 message
hi Sue welcome back
hi Sally welcome back
Note that as a side-effect the symbol name in the message block remains
bound to the value it was last associated with in the letter2 function:
>> reduce message
== ["hi" "Sally" "welcome back"]
If that should be relevant, i.e. you want to prevent the modification of
the binding of the word name in the original message block, you can use
bind/copy, which generates a duplicate of the block, before it binds it:
letter2: func [b] [
foreach name ["Sue" "Sally"] [
print bind/copy b 'name
]
]
>> letter2 message
hi Sue welcome back
hi Sally welcome back
>> reduce message
== ["hi" "Bob" "welcome back"]
Note that the word used as foreach's first argument (foreach name ...) is
not bound in the context of your letter2 function in which foreach is
evaluated. It is bound in the context of foreach.
Let us demonstrate that by collecting different instances of name into a
block. We being with the global instance:
>> names: []
== []
>> name: "This is the global instance of name."
== "This is the global instance of name."
>> insert tail names 'name
== []
>> names
== [name]
>> reduce names
== ["This is the global instance of name."]
Now a function that has a local instance of name
f: func [/local name] [
name: "This is the function's local instance of name."
insert tail names 'name
print "In f. Before foreach."
print mold names
print names
and includes a foreach loop that also uses an instance of the word (or
symbol) name:
foreach name ["This is the foreach instance of name."] [
insert tail names 'name
print "In foreach."
print mold names
print names
]
Now the complete f function including both instances of name:
f: func [/local name] [
name: "This is the function's local instance of name."
insert tail names 'name
print "In f. Before foreach."
print mold names
print names
foreach name ["This is the foreach instance of name."] [
insert tail names 'name
print "In foreach."
print mold names
print names
]
print "After foreach. In f."
print mold names
print names
]
... and let's run it:
>> f
In f. Before foreach.
[name name]
This is the global instance of name. This is the function's local instance
of name.
In foreach.
[name name name]
This is the global instance of name. This is the function's local instance
of name. This is the foreach instance of name.
After foreach. In f.
[name name name]
This is the global instance of name. This is the function's local instance
of name. This is the foreach instance of name.
Note that because we bound foreach's instance of name to the block's
context, and the block is defined globally, the context foreach's name has
been extended, i.e. it remains "alive".
Hope this helps a little.
Take Care,
At 01:02 PM 9/7/00 -0700, you wrote:
>>> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n print
reform reduce b] ]
>>> form
>== ["hi" name "welcome back"]
<<quoted lines omitted: 4>>
>hi bob welcome back
>... the only problem is I was hoping that the loop values in letter2 would
take precedence over the globally bound value of name and allow me to
create a form letter of sorts.
>Could anyone help with this please?
>
>Get your FREE Email and Voicemail at Lycos Communications at
>http://comm.lycos.com
>
;- Elan [ : - ) ]
author of REBOL: THE OFFICIAL GUIDE
REBOL Press: The Official Source for REBOL Books
http://www.REBOLpress.com
visit me at http://www.TechScribe.com
[7/12] from: lmecir:geocities at: 8-Sep-2000 21:38
Hi Elan,
you wrote:
> letter2: func [b] [
> foreach name ["Sue" "Sally"] [
<<quoted lines omitted: 3>>
> Here BIND directs REBOL to associate all words contained in 'b with the
> "closest" context that contains the symbol name.
L:
I would recommend to change the wording:
{Bind associates all words contained in B (not in 'B, because in 'B is
contained
a block IMHO) with the context previously associated with the
word 'Name (again, not Name, as you wrote) which is its second argument.}
I am not sure I understand the term "closest" above, I would recommend to
not use
it here.
Elan:
> Because
> 1. the context in which the BIND expression is being used is the block
> passed to foreach, and
L:
Again, a change suggested. I don't believe, that the block passed to Foreach
is a context, sorry. This wording looks better:
{The second argument of Bind is the word 'Name previously associated with
the context Foreach created.}
Elan:
> 2.
> a) because the first argument passed to foreach (foreach name ...) is an
> instance of the word name
L:
This doesn't make much sense to me too, the sentence: {'Name (the second
argument
of Bind above) is an instance of the Word! datatype} looks like a correct
usage of
the word "instance", but it doesn't say what you wanted. I would recommend
to look at the previous suggestion.
Elan:
> b) there therefore now exists an instance of the word name that is bound
to
> foreach's context,
L:
Again a change necessary, IMHO: {There exists a word 'Name that is bound to
a context Foreach created.} is the wording I prefer.
Elan:
> 3. ==> therefore
> a) REBOL will identify foreach's context as the "closest" context in which
> 'name occurs.
L:
I think, that you switched the cause and the consequence here: the truth is,
that the word
'Name above (the second argument of Bind) was bound by Foreach to the
context it created and that is why "there exists a word 'Name that is bound
to a context Foreach created".
Elan:
> This is the context to which all words in the block b are now
> being bound, provided they are defined in foreach's context.
> b) Because of 3.a) the symbol name in the block b will be bound to the
> foreach context. (If the block b contained other words and some or all of
> these other words were also defined in the foreach context, then all these
> words would be bound to the foreach context as well.
L:
I don't like the use of the word "symbol" here. The meaning of it is defined
in
Rebol. I found the use of this word in Rebol with different meaning,
than Rebol assigned to it ambiguous.
Elan:
> Words that are not
> defined in the foreach context remain bound to whichever context they
> originated in, when the block b was formed, or they remain unset!, if they
> were never set to a value to begin with).
L:
Again a statement I would suggest to change: {Words that are not contained
(whether defined or not is
irrelevant) in the context Foreach created remain unchanged, while words,
that are contained in the context Foreach created are replaced (in B) by
their equivalents bound to the above context.}
Elan:
> RESULT:
> >> name: "Bob"
<<quoted lines omitted: 13>>
> >> reduce message
> == ["hi" "Sally" "welcome back"]
L:
Yes, this effect can be considered a self-modification of the code
presented, I think.
Elan:
> If that should be relevant, i.e. you want to prevent the modification of
> the binding of the word name in the original message block, you can use
<<quoted lines omitted: 12>>
> not bound in the context of your letter2 function in which foreach is
> evaluated. It is bound in the context of foreach.
L:
A different wording: {Note that the word used as Foreach's first argument
(foreach name ...) is not bound in the context of your Letter2 function. It
is bound in the context Foreach created.}
I would prefer not saying, that "...Foreach is evaluated in a context,...",
because I don't know, what that should mean. To the contrary, I am pretty
sure, that there are examples of Rebol code, for which you cannot find any
context they are evaluated in
.
Elan:
> Let us demonstrate that by collecting different instances of name into a
> block. We being with the global instance:
<<quoted lines omitted: 61>>
> At 01:02 PM 9/7/00 -0700, you wrote:
> >>> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n
print
> reform reduce b] ]
> >
<<quoted lines omitted: 9>>
> >
> >... the only problem is I was hoping that the loop values in letter2
would
> take precedence over the globally bound value of name and allow me to
> create a form letter of sorts.
<<quoted lines omitted: 13>>
> http://www.REBOLpress.com
> visit me at http://www.TechScribe.com
Take Care,
Ladislav
[8/12] from: lmecir:geocities at: 8-Sep-2000 22:08
Hi,
<SS> wrote:
> I'll point out quickly that what you're trying to do is generally
> considered a bad programming practice, i.e. referencing a variable
<<quoted lines omitted: 6>>
> perhaps not one as much of scope but more of tokenization:
> >> letter2: func [b][foreach n ["sally" "sue"][print replace (copy b)
'name n]]
> >> greeting: ["hi" name "welcome back"]
> == ["hi" name "welcome back"]
<<quoted lines omitted: 8>>
> FWIW,
> <SS>
The self-modifying Bind-, or its non-self-modifying Bind/copy- variant
approach really doesn't look preferrably to me. Here is an approach that
looks different IMHO:
letter2: func [b /local subst][
subst: func [name] reduce [:print b]
foreach n ["sally" "sue"][subst n]
]
greeting: ["hi" name "welcome back"]
name: "bob"
letter2 greeting
What do you think?
Ladislav
>
> On Thu, 7 Sep 2000 [princepawn--lycos--com] wrote:
>
> > >> letter2: func [b /local name] [foreach n ["sally" "sue"][ name: n
print reform reduce b] ]
> >
> > >> form
<<quoted lines omitted: 8>>
> >
> > ... the only problem is I was hoping that the loop values in letter2
would take precedence over the globally bound value of name and allow me to
create a form letter of sorts.
[9/12] from: princepawn:lycos at: 8-Sep-2000 1:48
Oh my god. I think this is the most naive thing I have ever done in my life... I really
didnt even think that I had just redefined form.
This is so embarrassing.
---
On Fri, 8 Sep 2000 0:05 +020
alex.pini wrote:
[10/12] from: al:bri:xtra at: 9-Sep-2000 17:38
princepawn wrote:
> Oh my god. I think this is the most naive thing I have ever done in my
life... I really didn't even think that I had just redefined form.
> This is so embarrassing.
Don't be too embarrassed. I did a similar thing in my HTML dialect, and
accidentally redefined 'head. Took me a while to figure out that.
Best hint to avoid this problem is to use long descriptive names. Instead of
'form, use: 'form_letter.
Andrew Martin
ICQ: 26227169
http://members.xoom.com/AndrewMartin/
[11/12] from: agem:crosswinds at: 9-Sep-2000 13:19
protect-system 'protect-system 'protect-system ..
Volker
[Al--Bri--xtra--co--nz] wrote on 9-Sep-2000/17:38:16+12:00
[12/12] from: al:bri:xtra at: 10-Sep-2000 12:46
Volker wrote:
> 'protect-system 'protect-system 'protect-system ...
Definitely, that too! :-)
Andrew Martin
ICQ: 26227169
http://members.xoom.com/AndrewMartin/
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted
Librarian comment