META: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 META was invented. It did the only thing it could do:

  • When you META'd a plain (or quoted) thing, it got one quote level added

  • When you META'd an "antiform" you would get a plain version of the thing

So it worked like this:

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

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

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

>> meta 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: META 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 META was being invented. But regardless, it was initially decided that META and UNMETA 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 unmeta all [
        meta for-each var blk1 body  ; META NULL => NULL allows chaining BREAK
        meta 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, META of NULL fit into the regular pattern of all things having reified metaforms, giving ~null~.

I Wanted A META:LITE

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

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

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

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

>> meta:lite null
== ~null~  ; anti

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

So today's META: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 ~end~ and ~NaN~ as well):

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

But What If META: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 META:LITE take care of it?

>> meta:lite null
== ~null~  ; anti

>> meta: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 meta states. They just have to remember to use UNMETA:LITE on the reverse end. (If you use plain UNMETA it will catch your error, as UNMETA 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 META, 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 META:LITE be formulated as "do what META would do in a historical world where quasiforms and meta-nulls didn't exist" feels pretty good.

It's Still Fundamentally a "Valid META"

I couldn't really think of a good name for the operation besides just saying it was an alternate behavior of META. "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 META: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 META 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 META 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 META. I can't offhand think of a case where that would ever be useful.)