Hi Ladislav,

I had written:
>You had a problem with samef. I pointed out what the problem is

To which you responded:
>L>
>actually, you didn't find anything wrong on my approach,

I didn't? I sure did. You didn't take the time to review it, or you failed
to understand it. That's a shame, but no reason to get personal.

>just found another approach, 

I presented you with a correct approach so that - by comparing the two -
you would be able to figure out where you went wrong. I must admit that
presenting you with the material and letting you derive conclusions didn't
work as I expected it to, because you chose an unproductive form of "lazy
evaluation", namely, refusing to follow the argument instead of thinking
along.

Recall that my former email concluded by presenting you with both results:

Your implementation of samef:

>> samef: func [f [any-function!]] [func [x] [f x]]
>> a: samef :id
>> source a
a: func [x][f x]
>> b: samef :inc
>> source b
b: func [x][f x]
>> same? get first second :a get first second :b
== true

Using my version of samef:
>> samef: func [ f [any-function!] ] [
[      make function! first :f second :f
[    ]
>> a: samef :id
>> b: samef :inc
>> source a
a: func [x][x]
>> source b
b: func [x][x + 1]

The important lines to be compared are:
Yours:
>> a: samef :id
>> source a
a: func [x][f x]
>> b: samef :inc
>> source b
b: func [x][f x]

Compare to my samef implementation:
>> a: samef :id
>> b: samef :inc
>> source a
a: func [x][x]
>> source b
b: func [x][x + 1]

Some hints:
1. Using your version of samef, both functions 'a and 'b evaluate to 

func [x] [f x]

a) In which context is 'f bound to a value (it is not the global context!)
b) At which point will 'f be dereferenced?

2. Using my version of samef neither 'a nor 'b references 'f. But my samef
function also used 'f, in the process of constructing 'a and 'b.
a) In which context was 'f bound to a value (same as your version of samef)?
b) At which point was 'f dereferenced (not the same as your version of samef)?

3. If you haven't done that yet, try 
>> source func
and see whether that helps in determining why my version of samef acts
differently from yours. No, I wasn't trying to demonstrate that the samef
func could be written as:

samef: func [f [any-function!]] [ :f ]

I was making a statement about the difference between func and make
function!, which is relevant to explaining why my samef function generates
a different result from yours.

If you invest the effort of answering the above questions, you will find
that generally, your function fails because you disregarded the context in
which 'f is bound to a value and at which point 'f is dereferenced in that
context. If you had had that in mind you would have known that your
implementation of samef will not return the function passed to it, but
rather the symbol f, which will be bound to ... oops, now I'm almost giving
it away.

For the benefit of those of you, who don't know what on earth I'm talking
about, but would like to know:

Ladislav implemented a samef function like this:

samef: func [ f [any-function!] [ func [x] [f x] ]

He expected this samef function to return a function that would do the same
thing as the function passed to it. 

When he then did the following:

id: func [x] [x]
inc: func [x] [x + 1]

a: samef :id
b: samef :inc

then a did the same thing as b, namely evaluate :inc and not :id and both
functions ended up incrementing their argument by 1. 

He proposed that the correct way for REBOL to interpret his code was to let
'a continue applying :id to the function it was passed, while only 'b
should apply :inc.

He overlooked that using his samef function both a and b were bound to the
one and only instance of func [x] [f x], namely the one instance in the
body of samef, that instance in turn uses the word 'f, which is bound in
samef's argument block. Therefore, when f's binding was changed by evaluating

b: samef :inc

that change necessarily affected what 'f was bound to when 'a, which
references the value

func [x] [f x]

was evaluated subsequently. You see, 'a and 'b are different words, they
reference to look-alike functions, func [x] [f x]. The important thing here
is that - while both functions are look-alikes - there is only one unique x
and only one uniqe f. The x is a's and b's argument, it is bound in the
context of a and b to whatever value is passed to them, when they are being
evaluated. In contrast, f is bound in the context of samef and therefore -
and necessarily so - f cannot reference two different values, as just
mentioned, it will always reference that one value it is bound to in
samef's context. In our example that is first id's function. After samef is
called with :inc as its argument, 'f is bound to :inc in samef's argument
block and that becomes the valid binding for 'f for all functions who
depend on samef's context for the resolution of the symbol 'f.

Having ignored these minor details of how REBOL dereferences symbols,
Laidslav was surprised by the results he encountered and rushed to
judgement, calling his experience "Non-reentrant function calling", instead
of updating his understanding of REBOL's semantics.

The samef function example I produced was there to illustrate that if you
want samef to return the function it was passed, you must dereference 'f at
the time a and b are being created, and not allow 'f to be dereferenced at
the point in time a and b are being evaluated. You can achieve this by
using the notation

make function! first :f second :f

Here f is dereferenced at the time a and b are constructed and therefore
each of the two words is bound to the function it was intended to
reference, a references :id and b references :inc.

So, it's not true that 
>actually, you didn't find anything wrong on my approach,

What's wrong with your approach Ladislav is that you ignore when and in
which context 'f is bound to the function it references and:

>just found another approach, 

No, I presented you with some code that demonstrated that if you consider
when and where symbols are dereferenced, you can achieve your desired
results, showing you how f could be forced to be dereferenced during the
time the functions a and b were created, while preserving the pattern of
your implementation, i.e. not just returning the function passed to it, but
rather using make function! (which func uses as well) but in a way that
maintains the correct context and timing.

Elan


Reply via email to