Should REEVALUATE apply LET bindings?

So the idea of REEVALUATE (short name REEVAL) is that you get the same behavior "as if" you had written the thing in place:

>> x: 10
>> reeval (first [x:]) 20  ; acts like X: 10
>> x
== 20

But how far should this "as if you'd written it there" go? Should the binding be applied?

>> x: 1000
>> code: '(x + 20)
>> do [let x: 284, reeval code]
== ?

Does it see the new value for X? Should that give you 1020, or 304?

I vote 1020. Seems to me that only source-level code should see the LET's binding.

But there's an implementation problem because the evaluator has to know to suppress LET bindings on reevaluations. REEVAL takes pains to make sure it's running through the same code path as the evaluator normally would. It's not exactly clear what bits to check or flip to know how to control this behavior.

Tricky as that is, it would get even trickier if we said you wanted to apply the LET binding...because it gets hard to know whether you've applied it twice. Imagine if you said instead:

>> x: 1000
>> code: '(x + 20)
>> do compose [let x: 284, reeval '(code)]
== 304  ; we want it to see the LET X

How does REEVAL know if the let x: 284 was taken into account already or not? This depends on whether the argument was literal or fetched through a variable. But REEVAL isn't supposed to know anything about its argument besides its value. I rigged up a fix, and we can see how well it holds up.

I think this points to the idea that LET and USE should probably stick to having near-parity in outcomes. That means the binding only applies to source, not things fetched and then "treated as source" later.

Anyway, difficult stuff...all on the way to getting rid of FUNCT-behavior-of-FUNCTION. Since there's such a big monster of a codebase to try it on (including the Mezzanine, Rebmake, and ReplPad) it's getting exercised fairly heavily.