Now that $ means "produce bound form under evaluation", this would seem to suggest that the $x
form would be the consistent cue for "use existing binding".
>> foo: lambda [x] [
print [x]
for-each $x [1 2 3] [print [x]]
print [x]
]
>> foo 10
10
1
2
3
3
Does that mean we should switch to the idea of an evaluative argument for the parameter, where you pass 'x
or $x
?
Well...hold on a second. In both cases, the FOR-EACH would be receiving just the word X. But in one case it's bound, and in the other it is not.
Are we confident enough in bindings being under control that the "invisible" property of whether something is already bound or not can act as the cue for whether to create a new binding? (See related concern about MAKE OBJECT! having a SET-WORD! with a binding at the top level). I'm skeptical.
Also, consider when we want this:
x: 10
y: 20
for-each [x $y] [1 2 3 4] [
print [x y] ; 1 2 and then 3 4
]
print [x] ; 10 (undisturbed due to new binding)
print [y] ; 4 (reused variable)
Remember that both X and $Y
are unbound inside the block, but the block's environment has available bindings for X and Y going in. Then the $Y
signals in the "for-each variable dialect" to reuse the binding, while the plain X suggests not. It wouldn't matter if we did this with ['x $y]
, which I think is less desirable... the point is just that we wouldn't be doing this with [x y]
and forcing people to control it with unbindedness:
x: 10
y: 20
for-each compose [x (in [] 'y)] [...]
This suggests in the non-block case that it would be more conservative to take the parameter as an $arg
which would quote-but-bind, and then go off the cue of whether the $ was present or not.
And what about the potential contradiction, where you have a plain word and it's not unbound?
x: 10
y: 20
for-each compose [(in [] 'x) $y] [...]
Here the "dialect notation rule" says it's a plain word, hence you want a new binding. But it has a binding. Should that be an error to help point out the contention, or should it just assume the binding is superfluous?
Moreover... should a binding ever be treated as superfluous? This is a major question for consideration in the "mostly-unbound world".
Ripple Effect: Meta-Passthru LET Parameters
I'd just been thinking that the new FENCE! proposal would be able to solve something we couldn't really do before, which was mark a multi-return as being both ^META -and- the main overall result.
>> var: @z
>> [x {^y} (var)]: pack [1 2 3]
== '2
>> x
== 1
>> y
== '2
>> z
== 3
This wasn't achievable when marking the "circled" result was done with the @ symbol. Using the {FENCE!} to mark the circled result (defaults to first result) can accomplish it.
But if LET moves away from using quoted material to mean "don't create a new binding" and uses $, then there's a new contention: how to reuse an existing binding and make it meta.
>> (let [^x ...]: 1, x)
== '1
>> x: <before>
>> (let [$x ...]: 1, x)
== 1
>> x
== 1
>> let [???x??? ...]: 1
== '1
>> x
== '1
That shows an advantage of using the quote mark to say "have LET ignore this part", because it can mean ignore any part. So let ['^x]: ...
could achieve the intended purpose, telling the LET "this section isn't for you to worry about" and having it go through a step where it produces [^x]: ...
with the binding intact... falling through to the multi-return logic with whatever binding was in place (or whatever left-quoting construct wanted the SET-BLOCK).
So maybe LET just doesn't follow the same rule as FOR-EACH? Or maybe FOR-EACH should not be changed, and its unusual behavior of "using the binding of quoted things, but not of non-quoted things" should be left as-is?
x: 10
y: 20
for-each [x 'y] [1 2 3 4] [
print [x y] ; 1 2 and then 3 4
]
print [x] ; 10 (undisturbed due to new binding)
print [y] ; 4 (reused variable)
But this really feels backwards in a "quotes mean you don't get a binding" rule for the main evaluator.
It doesn't come up all that often. Maybe the following?...
>> let [$($ '^x) ...]: 1
== '1
>> x
== '1
"Give me a literal ^X that's bound. Then have the multi-return be guided by the meta that's on the word."
But that doesn't correspond to any of how SET or GET work... they're agnostic about the word type.
>> set ($ '^x) 1
== 1
>> x
== 1 ; not '1 (and I don't think it should be)
We could say that you can put the $ designator spaced off, and it's assumed to apply to the next thing:
>> let [$ ^x ...]: 1
== '1
This might not be a problem... although the LET still has to preprocess the bindings in the block. It's getting more invasive when it has to look into the details vs just say "oh, it's quoted, unquote it but ignore it otherwise."
Lots to think about here.
-
I do think the FOR-EACH etc. should be using the
$var
notation to mean "use existing binding".-
I doubt that it should be switched to for-each 'x and for-each ['x] for make new binding, but should stick with for-each x and for-each [x]
- I definitely don't think LET should be switching to let 'x: and let ['x]: for make new binding
-
-
Fences are going to probably be the right pick for "circling" which multi-return result to give back
-
If the $ operator is allowed to stand alone in the multi-return dialect, that probably gives full coverage of the need to opt out of LET creating a binding for some portion of a multi-return.
-
This makes the work LET does on the "dialect" it's processing inside a SET-BLOCK! more invasive than its former "if quoted, drop quote level and ignore" rule
-
It may be that LET's rules are just different from FOR-EACH's rules
-