typelevel / typelevel/cats-parse

Tuple semigroupal operations on parsers result in the wider Parser0 type - workarounds?

Open
#235 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Scala
Stars
245
Forks
51
Avg merge
3h 20m
Merged PRs (30d)
1

Description

The original design post contains this quite reasonable statement:

It is interesting to note how Parser1 composes with Parser: if you sequence one of each, you get a Parser1 as a result since once characters are consumed they are never unconsumed.

This is true when you use ~ to compose parsers:

val p1: Parser[A] = ...
val p2: Parser0[B] = ...

val combined1: Parser[(A, B)] = p1 ~ p2
val combined2: Parser[(B, A)] = p2.with1 ~ p1  // can use the with1 workaround if the left parser is Parser0

However, if you use the cats.syntax.contravariantSemigroupal operations to combine multiple parsers into a single tuple, to avoid working with nested tuples and for somewhat better syntax, this fails to work:

import cats.syntax.contravariantSemigroupal._

val p1: Parser[A] = ...
val p2: Parser0[B] = ...

// fails because p2 is Parser0, necessitating the use of Parser0 instances as they are "wider" in a sense,
// therefore `.tupled` returns `Parser0[(A, B)]`
val combined1: Parser[(A, B)] = (p1, p2).tupled

Is there a workaround for this, except using ~? The thing is, multiple ~s in a row result in the parser value being a lot of nested tuples, which doesn't look very nice:

(a ~ b ~ c ~ d ~ e).map {
  case ((((x1, x2), x3), x4), x5) =>
    ...
}

// vs tupled/mapN, if it was possible:

(a, b, c, d, e).mapN {
  (x1, x2, x3, x4, x5) =>
    ...
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Parser, Parser0, and cats.syntax.contravariantSemigroupal, focusing on tupled and mapN for mixed Parser and Parser0 values. Trace the relevant composition and type-inference behavior, then determine whether tuple composition can retain Parser; done should be a clear workaround or a resolved API behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
compilers
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.