Could we replace PARSE's OPT with TRY ?

The modern sense of TRY (circa 2023) works in concert with definitional errors to say "hey, wait, don't fail... you can be a no-op, that's fine."

For example:

>> block: []

>> take block
** Error: Cannot take from empty series position

>> try take block
== ~null~  ; isotope

This definition 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 parse looping construct more palatable, as try some is easier on the eyes than opt some.

Haskell Offers Precedent Using TRY This Way

Haskell has try defined as "Take a parser that may consume input, and on failure, go back to where we started and fail as if we didn't consume input."

If I'm reading that correctly, this is a parallel meaning to OPT.

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.
2 Likes

OPT isn't an English word. If you wanted one could try MAYBE

It's not? It's listed as a verb in most English dictionaries that I'm aware of.

1 Like

I'd been letting this turn over in my head a bit before committing to it (and deprecating OPT in the main UPARSE combinator set...though it would be defined in Redbol's parse a.k.a. PARSE2).

I started going through replacing it. For the most part I think it reads much smoother, yet there was a little bit of a speedbump when I saw it used with literals.

For example, changing:

parse url ["http" opt "s" "://gitlab.com/" ...]

To:

parse url ["http" try "s" "://gitlab.com/" ...]

TRY feels imperative...like it is telling you to attempt to run some function. While OPT feels more declarative... this is a thing that may or may not be there.

As it happens, it really is imperative: you are running a function... "s" produces a combinator. That combinator can be redefined in parse variants via the combinator map.

Yet it still felt a bit strange to me at first to say you were "trying S".

I think this is just a lack of familiarity, and it will seem more natural with time. Even looking at it now, I think the OPT is ugly, and I can rationalize why it's even probably better to have people think of it as "trying S".

I did give this a shot... and it can be argued to be the most coherent choice in reading:

parse url ["http" maybe "s" "://gitlab.com/" ...]

But its alignment with how MAYBE is used in the language to produce voids and invisibility is not clear. having MAYBE return null instead of void feels confusing. Whereas TRY will align more closely.

It feels safe to say that TRY is better than OPT when you look at the big picture. I don't think having synonyms in the default combinator set is a good idea, and so that rules out OPT. Perhaps MAYBE could be a combinator if we figure out what the difference is in a way that aligns with its other uses.

1 Like

So...we've had a good 7 months of TRY replacing OPT for me to get a truly informed feeling.

Getting cold feet... :ice_cube: :footprints: I don't 100% love it.

Nope. Still feels like the wrong part of speech.

And I don't think the idea that it relates to error suppression comes across meaningfully to users, especially since the errors of combinators already are suppressed and translated into mismatch-and-continue.

Beauty is in the eye of the beholder, I guess. People in Red certainly aren't bothered, and I'm probably the only person to have complained loudly about it.

If we made OPTIONAL a PARSE keyword and then said OPT was a shorthand for it, then that would at least offer a full-"English" choice:

parse url ["http" optional "s" "://gitlab.com/" ...]

parse url ["http" opt "s" "://gitlab.com/" ...]

I can see using it in tutorials, so it's less jarring. People would probably quickly switch to the abbreviation in practice. But I can't say that for sure... looking at the above, I might well write it out. :man_shrugging:

Guess it depends on how many times I'm using it. UPARSE offers more factoring capability than historical PARSE, so you don't wind up repeating yourself as often... and maybe being super brief in saying something is optional isn't that necessary.

Coming back to this... I still don't feel like I can justify it. MAYBE is for null-defusing. If it had a parse analogue, it would be more like this:

>> rule: null

>> parse "aaaccc" [some "a", some maybe rule, some "c"]
== "c"

I've said that we could not do this, because RULE fails at the moment of "combinating"... it can't look up the rule to form the subparser for [maybe rule], during the build of the parser for [some maybe rule]. So SOME is never called, hence it can never call MAYBE, where the logic to disable the error would live.

But...what if NULL did "combinate", just to a parser raising a specific error related to null combinators? Hm. The problem would be that parsers would have to default to promoting that error to a failure somehow. E.g. MAYBE would need to call its combinated parser with parser/null-error-ok or somesuch, to distinguish it from all the other parsers that don't want to be tolerant.

Or... maybe there's a specific recognition of the null-producing parser by its identity? e.g. the "null combinator" builds a parser that hard fails if it gets called, but MAYBE never makes that call...doing an inspection of it through some other means.

Though notice this usage wouldn't actually work anyway... SOME MAYBE RULE would make MAYBE RULE succeed without advancing, and be an infinite loop. (You can't use SOME OPT either with that meaning, for that matter...so not a complete indictment of the concept, just pointing out that it's not necessarily as useful as it seems at first.)

In any case, my bigger point being that I think this is the spirit of what a MAYBE combinator would be for... not imply generic mismatch tolerance. Just because it can't work mechanically for its natural meaning doesn't mean the word is up for grabs. And weighing it in my head right now, I kind of think it may be worth pushing through some tricks to do it...the idea of making the hard-failing combinator that's noticed by MAYBE's identity inspection on the parser sounds like it could work.

Odds Are, I'm Swapping The TRYs Back Out

Likely going back to a mix of OPTIONALs and OPTs... maybe see how favoring OPTIONAL works out in real code.

Just as a quick note: you’ve read this wrong. (Though to be fair it’s a bad comment from a little-used library.) The actual function of try is, ‘allow this parser to be rolled back on failure’. The stuff about ‘consuming input’ comes from a subtlety of parser combinator implementation, which is that they commit to a sub-parser as soon as it consumes a single element.

Of course, Haskell libraries must still offer a combinator for optional elements, which may be either present or absent. It’s an important aspect of parsing, after all. And they call it… optional.

1 Like