ENFIX vs LOOKBACK

One important change in Ren-C is that there is only one kind of FUNCTION!. It is, however, possible to make a specific word-to-function binding make that function to acquire its first argument from its left. This is done with a refinement to SET, originally called /LOOKBACK.

>> foo: func [a b] [print ["a is" a "and b is" b]

>> foo 1 2
a is 1 and b is 2

>> set/lookback 'bar :foo

>> 1 bar 2
a is 1 and b is 2

So there's technically no such thing as a "lookback function", just "lookback bindings"...and it will only act as a lookback if dispatched from that word. The moment you fetch a function out of a WORD!, that FUNCTION! has no "lookbackness".

As lookback became more sophisticated, it could hard quote... soft quote... or even complete a left-hand evaluation fully. This made it tempting to create a user-friendly infix operator to make it look more fluent. I called this operator enfix.

EN: a prefix occurring originally in loanwords from French and productive in English on this model, forming verbs with the general sense “to cause (a person or thing) to be in” the place, condition, or state named by the stem; more specifically, “to confine in or place on” (enshrine; enthrone; entomb); “to cause to be in” (enslave; entrust; enrich; encourage; endear); “to restrict” in the manner named by the stem, typically with the additional sense “on all sides, completely” (enwind; encircle; enclose; entwine). This prefix is also attached to verbs in order to make them transitive, or to give them a transitive marker if they are already transitive (enkindle; enliven; enshield; enface) via dictionary.com

So foo: enfix func [a b c] [print [a b c]] is just shorthand for set/lookback 'foo func [a b c] [print [a b c]].

It's a kind of nice play on words, in my opinion (though @asampal did not care for it). But I stopped saying that things were "lookback" and pretty much always started saying they had been "enfixed".

Remembering there's no such thing as an "enfix function" or a "lookback function" (only an enfixed binding or a lookback binding), one could still say "foo is enfix" or "foo is lookback". But lookback doesn't really have a good verb form, you can say "foo is enfixed" but not "foo is lookbacked".

Anyway, having two terms for the same thing is kind of confusing, so I've been thinking of getting rid of LOOKBACK entirely and changing the refinement to SET/ENFIX.

Any objections, or comments on whether the test on words should be called enfixed? or enfix?

Oh... I should point out, if the implication is not apparent, that ENFIX cannot possibly be an ordinary arity 1 "converter" that returns a FUNCTION!. It has to be an infix operator which quotes its left argument. Because if enfix took a function parameter, it would have no way to return a function that carried any information about the binding. e.g. there is no way to make this work:

foo: (enfix func [a b c] [print [a b c]])

In other words, anything that returns a FUNCTION! value returns it as the one-kind-of-function, and using a SET-WORD! ordinarily (without magic) will always default to prefix form.

What was the count against using tags to distinguish the nature of functions?

dot: func [<infix> this that][join-of this that]

"This" dot " and that"

The point raised above. Functions aren't infix/enfix. Variable bindings are. So any FUNCTION! returned from FUNC...then assigned through a set-word in the ordinary way...will lead the resulting WORD! to be prefix.

I'm happy with changing it to SET/ENFIX

However enfixed? or enfix? is harder to choose because i can see good reasons for both!

What's the plans about bind? and bound?. If we're moving to bound? usage then, on same note, enfixed? would win for me over enfix?.

1 Like

One thing that has changed the landscape a bit is that logic-returning specializations of things are now being shorthanded ending in ?. So instead of people writing true? find [...] ... (or the confusing found? find [...] ..., where FOUND? was just a synonym for the-function-formerly-known-as-TRUE?) you can just write find? [...] ..., because it is a CHAIN of FIND that feeds the output into TRUTHY?.

Hence one might think that bind? ... is a variant of BIND, taking the same parameters, but which chains so as to tell you whether the binding was successful, or, something otherwise LOGIC!-y about the result. :-/

So by this token I'd say it needs to be bound?. And while a logic-returning ENFIX verb doesn't make any real sense I could think of, the pattern of ?-ing verbs should probably stay as a ?-returning variant of the verb, not a property query.

Hence, you raise a compelling point. enfixed? it is.

While we're on this thread, what were the advantages with going for SETting an enfix word over MAKEing an enfix! / infix! / op!? datatype?

eg.

>> set/enfix 'x func [a b] []

over...

>> x: make enfix! func [a b] []

The original motivation was saying you're a function-taking-a-function, e.g. SORT taking a comparator. Why should you not be able to use :> as easily as you might use :greater? Why should you need to worry about functions you are passed somehow "reaching backwards" to grab parameters, and account for that... e.g. "if I was passed an enfix function, do ((left) comparator (right)), else do (comparator (left) (right))".

(In reality, the truth is more complex than this...due to parameter conventions. You can't really be agnostic about the functions you're getting in and call unknowns without knowing whether they quote or not, for instance. For safety you really should probably be using APPLY and build the frame yourself.)

But having just one type of FUNCTION!, and ensuring that anyone who passes a FUNCTION! as a value is passing what you experience as a non-enfix one...makes easier cases work. And at least lets the API for function introspection stay more regular. You don't wind up saying foo: func [some-func [function! enfix!] ...] [...] and have conditional behavior about it. If you can have one less datatype and get all the same power, you're better off.

That said, there's a kind of equivalence to it. It would not be that hard to change if someone thought of a good reason. So far, I see all the benefits on the OneFunction side, minus this one weird aspect of how setting the bit on the word needs to be done. But it doesn't seem unfathomable.

1 Like

Okay, the deed is done. I cleaned up some junk and updated comments while I was at it.

For those who want to ponder the hard-to-ponder, should 0-arity enfix functions exist?