It's Not "Corruption"... It's The Best Strategy
I've looked at enough cases to know that a VOID! and empty PACK! are interchangeable a lot of the time. This is why they are called "VOID" and "HEAVY VOID"... and both answer truthy to ANY-VOID?. It's par for the course in the isotopic model.
Think about examples like this:
>> plusones: []
>> map-each x [1 2 3 4 5] [append plusones x + 1, if odd? x [x * 10]]
== [10 30 50]
>> plusones
== [2 3 4 5 6]
IF returns a VOID! when it doesn't take its branch. But you wouldn't want that MAP-EACH to give [10 [2 3] 30 [2 3 4 5] 50]. So you see why IF isn't vanishable.
Doing the "distortion" to the heavy void here was very useful, and I think the MAP-EACH result is exactly what you would want.
(Related discussion: "Choosing Between Returning VOID and HEAVY VOID")
YES
... EVAL Has
Modes Of Operation
-
"transparent" mode - like how GROUP! works, where
(expr)andexprbehave the same, at the cost of having distinct behavior for all steps producing VOID! up until the first non-VOID! value. (No need to use the^operator in those initial steps.)-
you wouldn't want
void? (eval [^ comment "hi"])to be falsey. It needs the same answer asvoid? eval [^ comment "hi"]which is truthy. -
Merely parenthesizing a single expression isn't expected to change what it produces.
-
-
"regimented" mode - like how
eval blockis expected to work, where every step has the same "afraid of ghosts" behavior, even before the first non-VOID! value is seen.-
The consequence of this is that
eval [expr]may give a HEAVY VOID answer when plainexprwould have given a "light" VOID -
This makes it trivial to simulate the exact answer of a full
EVALusing sequentialEVAL:STEPcalls, and just throwing away any VOID!s.
-
These two modes could be controlled by a refinement, rather than being based on the datatype. But that would require coming up with a name...and also wouldn't draw attention to the reason the modes are distinct, and specially fit to their types.
By guiding the behavior by the type, this increases the odds that people will use the right evaluation...or at least think about why the distinction exists.
To further the prescriptiveness to try and guide people to the coherent answer, GROUP! does not support EVAL:STEP. Because if it did, then getting the same answer that a non-stepping evaluation would get would involve switching modes after you saw a step that produced a non-ghost (e.g. stop passing in whatever :UNAFRAID refinement, or in this case switching from passing a group to passing a block).
If you want to evaluate a block with group semantics or vice-versa, use the AS operator:
>> eval as group! [eval [comment "hi"]]
== \~\ ; antiform (void!)
>> eval as block! $(eval [comment "hi"])
== \~()~\ ; antiform (pack!) "heavy void"