Back To Basics: What About (almost) NO SET-BLOCK! Behavior?
I realized that what I was trying to do was to split the behavior of multiple returns across two parts: the SET-BLOCK! on the left, and the function dispatcher mechanics on the right.
However you slice that, it means the SET-BLOCK! winds up asking for something from its right-hand side besides "give me the single result of your evaluation". That requires baking some kind of protocol in at a pretty deep level.
But what if SET-BLOCK! was "dumb" by default. All it would do would be to set the first item to the evaluation of the right hand side, and unset the rest:
>> [x y]: 1020
>> unset? 'y
Then we could basically say that all multi-return functions are actually enfix, and take a SET-BLOCK! on the left hand side that's
They'd have a little prelude which would evaluate any groups in the block on the left hand side first (so things are coherent left=>right). Then they'd run their body, and have an epilogue which did the writeback to the variables.
Well, yes. And it's how UNPACK works.
I never said making all FUNCs that were multi-return implement themselves as enfix was a bad idea.
In fact, given UNPACK as an example...I think it shows that a sort of "sky's the limit" definition of how your function chooses to interact with a SET-BLOCK! is really more interesting than trying to come up with some standard definition of what a "multi-return" is.
[<special-instruction> a *]: your-special-function ...
We can have some basic expectations (and if you're going to use an unmodified LET you'll have to accept a few of those, though it passes through TAG!s and such).
Equally Broken with GROUP!s, but Answers for APPLY etc.
Trying to formalize multi-return beyond enfix wasn't really leading to anything better.
For instance, allowing GROUP!s might sound nice, which enfix definitely can't do:
[value rest]: transcode data
[value rest]: (transcode data)
But once you're "inside the system" with the power to do more, do you really want to? What about:
[value rest]: (transcode data, 1 + 2)
[value rest]: ((^(transcode data)))
Trying to pick which of these situations you're going to rig a protocol around is dicey. Also, how would you solve something like:
[value rest]: apply :transcode [data]
The enfix actually gives us an answer. APPLY can just notice that :transcode is interested in things on its left hand side, and give it the SET-BLOCK!...proxied as a parameter. The same thing will work for UNPACK, even with things like its weird ellipsis semantics for "ignore additional values":
>> [a b ...]: apply :unpack [reverse [<dropme> 304 1020]]
So being dumber is actually smarter, in this particular case.