Implicit Escaping To Tiebreak Literal Arguments

Imagine a situation where one function takes its right-hand side literally, and another takes its left-hand side literally:

right-literal: func ['arg] [...]
left-literal: enfix func ['left right] [...]

What happens when I write:

 right-literal X left-literal Y

Seems like an unbreakable tie. :necktie:

You're going to be lying to someone if you don't trigger an error. It could be a pretty big lie...e.g. if you let one evaluate and pass their result to the other, then you might be giving an antiform to a function that specifically only expected source-representable things.

But what if the situation was a bit more...malleable...

Let's say that one of these lets you escape the argument inside a GROUP! (currently thinking the most semiotic way to represent such a property of a parameter is by...putting it in a group).

right-escapable: func ['(arg)] [...]  ; `right-esc ('X)` acts like `right-esc X` 
left-literal: enfix func ['left right] [...]

So this means that RIGHT-ESCAPABLE is geared up to accept evaluative products. If that's the case, then we might think of ourselves as having a bit more liberty to tiebreak:

right-escapable X left-literal Y
=>
right-escapable (X left-literal Y)

Whether that seems presumptuous or not to you, it definitely is useful, e.g. with lambdas...where requiring a group would be ugly:

case [...] then x -> [...]

The interface on the function says it was "willing to accept a group at the callsite". But it never actually received a group, just the evaluative product, which would then be typechecked. Given that it's willing to take that evaluative product, why not throw in the group implicitly vs. giving an error?

You should be convinced. It's a good thing.

Another Case Study: Infix "OF"

First there was (type? x) in Rebol2

Then (type-of x) emerged, in the attempts to purge the blight of "functions that return a result end in question mark", reserving it for LOGIC-bearing functions.

It then became (type of x) to be even more pleasing to the words-separated-by-spaces aesthetic.

But the infix properties of such a left-literal function can't be the same as ordinary evaluative infix, e.g. math:

>> 1 + 2 * 3
== 9  ; e.g. (1 + 2) * 3

Because we used to be able to write:

>> integer! = type-of 1
== ~okay~  ; anti

So we'd still like to be able to write:

>> integer! = type of 1
== ~okay~  ; anti

Hence that can't be interpreted as (integer! = type) of 1

"Easy enough" you say... "make it so literal left enfix wins over evaluative right enfix."

If you think it's easy, try writing this stuff yourself. But yes--that is what I did.

However, OF is one of these "escapable" routines. We want to be able to do this:

>> integer! = (first [type length]) of 1
== ~okay~  ; anti

So how does this work out with our tie-breaking?

It doesn't count. There's no tie to break. = isn't inescapably quoting its right. If it was inescapably quoting its right, then the escapable left would mean the OF would yield to the hard rightward literal.

It's Simpler Than I Had It

Due to some accidents of history and not really having clear thinking on this, there were more parameter conventions than were required... with one hacked in to specifically make the OF case work.

It turns out that using the rationale above, the extra parameter convention can be dropped. It can all be done with just escapability-or-not meeting escapability-or-not.

1 Like