Could we replace PARSE's OPT with TRY ?

Just a week ago, things stood at the idea that TRY was for "defusing NULL" by turning it into a BLANK!:

>> try null
== _  ; tolerated by some functions that would not tolerate NULL

But that's all out the window, now. TRY is for saying "hey, wait, don't fail... you can be a no-op, that's fine." Nothing to do with blanks anymore.

This makes it a candidate for being a very literate alternative to OPT in parse!

>> parse "aaaccc" [some "a", try some "b", some "c"]
== "c"

It helps make the loss of "ANY" as a looping construct more palatable, as try some is easier on the eyes than opt some.

But...what about conflation with the purpose of defusing NULL arguments?

>> rule: null

>> parse "aaaccc" [some "a", try some rule, some "c"]
== "c"  ; ???

Hmmm. And what if you wanted to require it unless it was null?

>> rule: "b"

>> parse "aaaccc" [some "a", try some rule, some "c"]
; null  (e.g. conceptually I was TRY-ing RULE, not the SOME)

That doesn't feel right. And I don't like the idea that we'd be seeing things like opt try some rule on any kind of regular basis.

Let's Remember: This is a Dialect

Things are already stretched around a bit, and we make things line up when they make sense...and unalign them when they do not.

We're free to say that TRY has nothing (or little?) to do with tolerating NULL inputs to parse rules, but where it shares heritage in meaning is "a no-op here is okay".

I think there are two reasonable options:

  1. Keep the current policy that most times, passing a NULL to rules is an error. If you want a no-op rule, use [] or for more efficiency, (the ') (a quoted null)

    • So this would mean that the decision is on a per-combinator basis, vs. saying all parser arguments to combinators are implicitly [<try>] ... and so things like SOME would not choose to label its argument that way.

    • Exceptions could be made for things like SEEK, where try seek (null) would be a way to say it's okay if you don't provide a seek position.

  2. Systemically allow conflation on all combinators, where some null errors but try some null is legal.

Off the top of my head here, I think (1) is probably the better choice. If someone disagrees, we might want to make it easier to change via a switch vs. having to copy all the combinators and add <try> to their arguments.

But I definitely don't like the idea that a rule prefaced with TRY would be expected to succeed if its argument were non-null. TRY should mean the rule cannot fail its match (other than by raising an error).

1 Like

Potentially influencing this, is that I've rewritten the inner guts of UPARSE such that definitional errors are used to signal a combinator failure...not "pure" NULL.

In the original concept, I'd been playing on the difference between null isotopes and pure NULL--to distinguish when a combinator "actually returned null" vs. when it wanted to indicate a mismatched rule failure. But using a definitional error is a cleaner solution, that really allows a combinator to synthesize any value.

  • It could mean that TRY makes more sense. It could leverage the same error, and any infix operations that work with it (e.g. if an ELSE-like construct reacts to the same error as TRY).

  • Though it might make less sense... as combinators that raise definitional errors are already sort of being TRY'd and having their errors defused... then moving on to the next alternate. :thinking:

    • So the TRY has in effect already happened, and you're asking it to take an additional disposition of not moving on to the next alternate.

I'm somewhat uncomfortable conflating the two concepts:

  1. "it's okay if the specification I give you is too incomplete for you to test for a match"

  2. "it's okay if you can't match a completely specified rule"

It feels like this would cover up errors.

So far, we've been getting by with NULL rules being illegal, always.

But think about something like CURTAIL, which doesn't have to do with whether the rule match is successful or not, but defusing constructs that complain about NULL:

>> rule: null

>> parse "a" ["a" rule]
** Error: RULE is NULL

>> parse "a" ["a" curtail rule] 
== "a"  ; e.g. curtail was void

So if you used CURTAIL and your rule wasn't null, it would have to match... it's the rule that's optional, not the matching:

 >> rule: [some "b"]

 >> parse "a" ["a" curtail rule]
 ; null

 >> parse "abbb" ["a" curtail rule]
 == "b"