Typechecking Quoted forms / Quasiforms / Antiforms

Asking questions about antiforms can be a bit tricky.

If you have a lifted result that contains something that might be a pack, you'd have to say:

if pack? unlift result' [...]

But you're just asking a question. What if it contained a lift of an ERROR! antiform? Should PACK? be willing to accept ERROR! ? If not, that would cause an abrupt failure.

To dodge the need to do an UNLIFT, you could say:

all [
    quasiform? result'
    block! = heart of result'
] then [
   ...
]

And via such a mechanism, you could write a function LIFTED-PACK? that would not fail on LIFTED-ERROR!:

if lifted-pack? result' [...]

That has the nice feature of not forcing you to perform an UNLIFT just to answer the question. You can narrowly ask "is this a lifted pack".

But I think such things need to be in the box. This question gets asked a lot, and I'm tired of asking it as the ugly and breakable pack? unlift.

What If Typecheck Functions Had a :LIFTED refinement...?

It doesn't seem like clogging up the namespace with more functions makes a lot of sense, so we might offer a refinement:

if pack?:lifted result' [...]

We could put a question mark on the refinement as well :face_with_diagonal_mouth:

if pack?:lifted? result' [...]

Okay, no, we won't do that.

I kind of feel like putting the LIFTED after makes it unclear. You'd read it like pack? lift result'. Does that mean it should just be UNLIFT?

if pack?:unlift result' [...]

But at that point, people are probably not going to generally know what the difference is between that and pack? unlift result

None of this is as good as simply lifted-pack?. But we don't want to generate new words for every possible thing (and questions like lifted-integer? are equally legitimate...)

What About Arbitrary CHAIN! Interpretation?

Let's forget for a moment about the existing refinements to LIFTED and QUASI. What if they--as functions--were willing to take other functions as a refinement?

if lifted:pack? result' [...]

This could be a general pattern of solution...

if (quasi:group? first [~(a b c)~]) [...]

if (quote:word? first ['a b c:]) [...]  ; or quoted:word?

How would it work? Well, I guess the basic idea would be that it would do a processing step on the argument before typechecking it and passing it to the constraint function.

So quoted:word? would run QUOTED, and it would be able to inspect the chain as containing WORD?.

  • If it was passed something like <foo> it would say "I don't even have to ask, that's not a quoted anything".

  • If it was something like '<foo> it would say "okay that's quoted, I need to ask" and it would unquote the thing before passing it to WORD?, which would come back false.

  • If it was 'bar it would do the same thing but this time WORD? would return true.

It feels a little bit ad-hoc, but the ergonomics are certainly there. This would be tremendously useful and could create new and useful type constraints. It's literate... and lifted:pack? is going to look better in type specs than lifted/pack?

Not only that, but recognizing "intrinsics" in the chain would mean this could be relatively fast--faster than pack? unlift could be.

What About Refinements Like LIFT:LITE

Let's say there's a single-arity logic-bearing function someone makes called LITE, and they get mad that LIFT:LITE doesn't call it to do a meta version of that test.

I don't know that I care a ton about that. We have situations in PARSE where you might have a variable named ACROSS and it will ignore that variable if there's a keyword called ACROSS. You have to escape your words when they run up against reserved dialect words.

So I guess you'd wind up with something like:

 if lifted:(lite/) [...]

Otherwise the keyword would win.

What About Cascading The Functions?

if (quoted:quoted:quasi:block? first [''~[a b c]~]) [...]

Well I guess that could work if the rule was that if you used a function name as a refinement, that function would receive all the refinements after it. Applying that recursively you'd get something that works.

There could be an optimization that functions like QUOTED would detect when the functions in the chain were ones they recognized, and they could do something optimal.

Does Any Of This Solve The UNLIFT Problem?

It's nice syntax, but remember the original issue...where you have a lifted-error-antiform, and you want to test it to see if it is or isn't a lifted pack:

if pack? unlift result' [...]

I'm talking about redoing that:

if lift:pack? result' [...]

But if LIFTED is unlift'ing its argument, and passing it to PACK?, does that still have the same problem?

It doesn't have to. LIFTED would see that the result is a quasiform, hence a candidate for any function to ask... then it needs to typecheck against what PACK? takes. But if that typecheck fails, there's no need to raise the error. You can just say "no, it's not a lifted pack". Done.

Are There Less Wacky Ways To Do It?

I dunno. It's admittedly a bit weird to put that much overloading on words like LIFT and QUASI. Their type signatures stop making sense (returning LOGIC?...sometimes?)

The overloading could be reduced if the weird modifiers were QUOTED, LIFTED, and QUASID. :-/

if quasid:pack? result' [...]

Errr, no. Didn't come this far to write things that look like garbage.

But oddly, quoted:xxx? looks better than quote:xxx?... does that suggest the operator should be called QUOTED too? :thinking:

>> quoted 1 + 2
== '3

I've seen it as QUOTE for so long that it's hard to frame it. It doesn't look terrible, and when you put them side by side the brevity has an advantage:

if (quoted:quoted:quasi:block? first [''~[a b c]~]) [...]

if (quote:quote:quasi:block? first [''~[a b c]~]) [...]

To say that 'a is a QUOTE-WORD! is a little bit caveman-ish, but better than calling it a LIT-WORD!, and it takes one less syllable to say "is a quote word" than to say "is a quote-uhd word".

Looking at it in that light, it's growing on me to dumb it down. Maybe not in all circumstances. Perhaps it could be left as a matter of taste with QUOTED and QUOTE being synonyms... like FUNC and FUNCTION, use whichever you want.

I Think This Is A Direction Worth Pursuing

I've been looking for an answer to this question, and haven't thought of anything this good before.

Don't have a complete design for the "customized refinement dialect", but I can do some prototyping...