LIFT:LITE - When You Don't Want Quasiforms

There was a time before quasiforms existed, but where there was generic quoting.

It was in this time that LIFT was invented. It did the only thing it could do:

  • When you LIFT-ed a plain (or quoted) thing, it got one quote level added

  • When you UNLIFT-ed an "antiform" you would get a plain version of the thing

So it worked like this:

>> lift first [(d e f)]
== '(d e f)

>> lift first ['(d e f)]
== ''(d e f)

>> spread [a b c]
== \(a b c)\  ; antiform

>> lift spread [a b c]
== (a b c)

(That's not how it works now--for good reasons. Not only is it a bit too easy to get confused about whether a meta protocol is in effect, the absence of quasiforms leaves a representational hole for values that produce antiforms under evaluation. But I won't rewrite a A Justification Of Generalized Iostopes here, this post has another purpose.)

Another Historical Twist: LIFT of NULL was NULL

NULL was an outlier--at various times having no quoted form (and at other times being considered a quote of nothingness, e.g. the lone apostrophe (')).

I don't exactly remember what state NULL was in at the time LIFT was being invented. But regardless, it was initially decided that LIFT and UNLIFT of NULL could just give null back.

This actually turned out to frequently be useful...for instance when writing a loop wrapper like FOR-BOTH

for-both: func [var blk1 blk2 body] [  ; the historical formulation
    return unlift all [
        lift for-each var blk1 body  ; LIFT NULL => NULL allows chaining BREAK
        lift for-each var blk2 body
    ]
]

Though while it was useful there, plenty of places needed to speak fully abstractly about all possible states. So as the model shaped up, LIFT of NULL fit into the regular pattern of all things having reified lifts, giving ~null~.

I Wanted A LIFT:LITE

The idea of a LIFT variation that passed through keywords as-is came along as lift:lite.

>> lift:lite [a b c]
== '[a b c]

>> spread [a b c]
== \~(a b c)~\  ; antiform

>> lift:lite spread [a b c]
== ~(a b c)~

>> lift:lite null
== \~null~\  ; antiform

>> lift:lite first [~null~ ~void~]
== '~null~

So today's LIFT:LITE still produces quasiforms for antiforms--just not for the ~null~ and ~[]~ void antiforms (and I now imagine it should probably pass through ~okay~ and ~NaN~ as well):

for-both: func [var blk1 blk2 body] [
    return unlift:lite all [
        lift:lite for-each var blk1 body  ; lift:lite null => ~null~ antiform
        lift:lite for-each var blk2 body  ; lift:lite void => ~[]~ antiform
    ]
]

But What If LIFT:LITE Didn't Make Any Quasiforms At All?

By design, quasiforms are not very friendly. So if you have an antiform in your hand... and you know you have an antiform in your hand... it's easy to take a step to a quasiform, but you need another step to get back to a plain form you can interact with.

So why not have LIFT:LITE take care of it?

>> lift:lite null
== \~null~\  ; antiform

>> lift:lite spread [a b c]
== (a b c)

This doesn't make a difference to things like FOR-BOTH. They'll still work--plain forms are just as truthy as quasiforms for the lifted states. They just have to remember to use UNLIFT:LITE on the reverse end. (If you use plain UNLIFT it will catch your error, as UNLIFT does not accept plain forms.)

It might seem random to pair up the feature of not making quasiforms with passing thru null and void. But I actually think the kinds of places where you'd want one behavior do overlap significantly with the other.

And we're really just running out of terms, here. Throwing another nuance in to say "I want partial LIFT, but only partial in the sense that I'm passing through null and void, not partial in terms of the other antiforms--make those quasiforms" is just starting to go beyond the ability to give names to.

So in my head, having LIFT:LITE be formulated as "do what LIFT would do in a historical world where quasiforms and meta-nulls didn't exist" feels pretty good.

It's Still Fundamentally a "Valid LIFT"

I couldn't really think of a good name for the operation besides just saying it was an alternate behavior of LIFT. "Lite" is a bit strange but I felt it fit.

Note that it doesn't make sense as a refinement to REIFY. Because being willing to produce something that can't be put in a block fundamentally undermines what the word REIFY means. (reify:...NOT!)

The thing about LIFT:LITE is that it really is giving you a full-spectrum meta representation of what you had in your hand. Every input state maps to a unique output state. The default LIFT happens to also be a fully reifying operation as well...but here we are saying that's not intrinsic to "a meta operation".

(Would there be any use for a LIFT that passes through all antiforms--not just the antiform words--and just quotes everything else? That's more a variation of QUOTE than it is a variation of LIFT. I can't offhand think of a case where that would ever be useful.)