Infixedness is a property that FRAME! cells can carry. There are 4 states that consume 2 bits:
-
"Prefix" (not infixed at all)
-
"Normal" Infix (sees exactly one item to the left, processed before the previous expression is allowed to run)
-
"Deferred" Infix (exactly one evaluation is performed to the left, which is needed by ELSE such that cases like
if x [y] else [z]
can act as(if x [y]) else [z]
instead ofif x ([y] else [z])
) -
"Postponed" Infix" (all evaluations on the left that can complete are run before running the operation)
Antiform FRAME!s can carry these infix states. And the space is available in plain frames as well, so we could make FRAME!s that are created from antiforms carry it, so that it round-trips:
>> f: copy unrun +/
== #[frame! [
value1: #[parameter! [char? any-scalar? date!]]
value2: #[parameter! [char? any-scalar? date!]]
]]
>> /plus: anti f
== ~#[frame! "plus" []]]~ ; anti
>> 10 plus 20
== 30
But... What About Specialization?
Let's say I'd done this:
>> f: copy unrun +/
== #[frame! [
value1: #[parameter! [char? any-scalar? date!]]
value2: #[parameter! [char? any-scalar? date!]]
]]
>> value1: 10
>> /plus: anti f
== ~#[frame! "plus" []]]~ ; anti
If the FRAME! kept its infixedness, then you'd have (20 plus) = 30
.
But I don't think that makes much sense.
Functions that take arguments infix tend to intend that infixness to apply specifically to a parameter. Like if (x: default [10 + 20])
has the variable specialized as x, you never intend to see ([10 + 20] specialized-default)
So Shouldn't Infixedness Be a PARAMETER! Property?
You might think that.
So why is the property carried by the Cell of the overall FRAME! as a whole?
The idea was to make it cheap to make a function that was defined normally to become infix...without allocating a new list of parameters:
/+: infix add/ ; no new parameter list made if it's just fiddling cell bits
If + and ADD have the same definition then their PARAMETER! can only have one state, so the bit has to go elsewhere.
Fundamentally one might reimagine INFIX as an operator that acts on PARAMETER!, and then see turning a function infix as a specialization operation:
>> add.value1.spec
== [char? any-scalar? date!]
>> /+: specialize add/ [value1: infix add.value1]
== ~#[frame! [value1] "add" [value2]]]~ ; anti
More of a pain. And now we face the question: what happens when a parameter is marked infix but isn't the first unspecialized argument? There's no way in the mechanics of the system to give that meaning.
>> /++: specialize add/ [value1: infix add.value1, value2: infix add.value2]
== ~#[frame! [value1 value2] "add"]]~ ; anti
>> 10 20 ++ ; incoherent, evaluator can't do this
== 30
So this is why infixedness has persisted as a Cell state, not a PARAMETER! state. Keeping it off the parameters avoids having to figure out how to handle the meaningless states. And it's cheaper to not create a new parameter list.
Ok. Any Bright Ideas On Managing These Bits?
The question is if we know which parameter is the infix one, so that if it's specialized out the infixedness goes away.
This means somehow the operation of turning a frame infix has to capture a memory of what parameter was infix at that moment.
That's more than 2 bits of information.
I don't have great ideas at this precise moment for how to do this, without making a copy of the parameter list.
The easiest thing to do is to say the infix state only applies to antiforms, and if you specialize things you have to re-infix them. Or maybe just refuse to specialize infix things, and say you have to drop the bits consciously to know you're doing that, and then re-infix them.
(Sometimes I start these posts thinking "I'll have a solution by the end" and then don't. Anyway, I'm going to stop thinking about this and work on other things for now.)