The vanishing intent of GHOST! (antiform COMMA!) is now distinct from the empty intent of VOID (empty parameter pack, antiform BLOCK!).
>> 1 + 2 ghost
== 3
>> 1 + 2 void
== ~[]~ ; anti
This has brought to the forefront the question of which combinators should support vanishing.
Right Now, If <END>
Matches, it Vanishes
>> parse [a b] [word! <end>]
** Error: PARSE mismatch
>> parse [a] [word! <end>]
== a
That's very useful.
Should TO and THRU--when parameterized with something that vanishes--also vanish?
>> parse [a #b #c] [word! to <end>]
== a
Seems pretty useful on the surface. But TO and THRU are intrinsically looping constructs...they iterate their rules. This means you could wind up with something that sometimes vanishes, and sometimes does not:
>> rule: [integer! | elide text!]
>> parse [a #b #c "hi"] [var: [word!, thru rule]]
== a ; VAR got the product of WORD!
>> parse [a #b #c 1020] [var: [word!, thru rule]]
== 1020 ; VAR got the product of THRU RULE
That's a bit disorienting, how an elide managed to leak out. It's like the structure of the parse code isn't doing what you expect.
This is why the main evaluator's loops and branching constructs are not willing to vaporize when they stand alone. They're only willing to produce VOID. This keeps the basic structure of the code from picking up results you don't expect, unless you call something that specifically is known to have vanishing intent (and you can ask to convert voids to ghosts explicitly if you want).
Even invoking a rule BLOCK! itself--if you think of rule invocation as like PARSE's version of calling a lambda--raises some questions about "surprising" ghosts:
>> rule: [integer! | elide text!]
>> parse [a #b #c "hi"] [var: [word!, rule]]
== a ; VAR got the product of WORD!
>> parse [a #b #c 1020] [var: [word!, rule]]
== 1020 ; VAR got the product of RULE
Unfortunately PARSE doesn't have the analogue of the GROUP! vs. BLOCK! distinction for code, where one can be transparent and the other "surprising". [elide some [rule1 | rule2]]
can be genuinely useful as a source grouping.
On That Note, Should LAMBDA Be Willing To Vanish?
At the moment, you get VOID and not GHOST from lambdas whose bodies vanish.
>> test: lambda [] [comment "this is a test"]
>> 1 + 2 test
== ~[]~ ; anti (void)
It's hence impossible for a LAMBDA to produce a GHOST!... you have to use functions with a return value. But does that make sense?
I think I'm willing to say that lambdas and rule blocks can vanish. They probably have to.
But I'm just not 100% on board with the idea of this vanishing leaking out through other constructs. It seems likely that you'd start getting "vanishing sometimes" behavior on accident.
So while it may seem nice if you're just looking at the specific case of to <end>
vanishing, I think the long game favors saying that it's easy enough to write elide to <end>
if you want.
Having plain <end>
in isolation vanish is fine, because that's predictable and happens every time you use <end>
. But it wouldn't be so with vanishing every time you use TO... hence the problem with it.