Skip to content

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

@netvl

Description

@netvl

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) =>
    ...
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions