Skip to content

result selector

GregRos edited this page Mar 26, 2025 · 3 revisions

When we apply complex combinators such as ⚙️many#sepBy, we often have several input parsers going into the combinator.

In many parser-combinator libraries, the results of these parsers are typically discarded. But often you do actually want to keep them, and I want to give users the ability to do just that.

This is where result selection comes in — a pattern that exists in many combinator constructors.

These constructors allow you to pass a callback that will project the result of the 🧩subject together with that of the input parser in some way. The exact way this works differs from one combinator to another.

All of these results are packaged into an object.

For example, in the case of many().sepBy(), the projection is applied to each [subject, seprator] result pair. In other words, it projects elements rather than the entire accumulated result.

The final separator argument will be undefined if there was no trailing separator

int
  .pipe(many().sepBy(string(" + ", " - "), (pair) => [pair.subj, pair.sep]))
  .parse("1 + 1 - 2"); // [[1, " + "], [1, " - "], [2, ]]

But in the case of the ⚙️many#till booster, the input parser only has one result. So the projection is applied to the subject’s accumulated results and the input parser’s single result:

string("x").pipe(
  many().till("y", (obj: { subj: string[]; till: string }) => [...main, till])
);
  • In a more general sense, the result selector signature’s should be carefully chosen to maximize its utility
  • Only combinators that would normally discard results actually need this feature.
Clone this wiki locally