Accepted answer

It's possible with Shapeless2 library. For given:

 object MyParser extends scala.util.parsing.combinator.RegexParsers   
 import MyParser._     

 val foo: Parser[String] = "foo"
 val bar: Parser[String] = "bar"
 val car: Parser[String] = "car"

 case class Record(f: String, b: String, c: String)

You can combine parsers using generic foldRight intead of ~:

 import shapeless._
 object f extends Poly2 { 
  implicit def parser[T, U <: HList] = 
   at[Parser[T], Parser[U]]{(a, b) => 
     for {aa <- a; bb <- b} yield aa :: bb  

 val p: Parser[Record] = (foo :: bar :: car :: HNil)


 scala> parseAll(p, "foo bar car").get
 res50: Record = Record(foo,bar,car)

P.S. The problem with built-in scala functionality is that they built ~-based typed binary tree, which is hard to traverse and flatten to tuple. Shapeless solves this problem - it has it's own ::-based binary tree called HList, it's simmilar but has interesting operations, like convertion to tuples or case classes (probably macro-based). In this example I use foldLeft to build Shapeless-hlist and for-comprehension (expands to flatMap on parser) to combine parsers as they have monadic nature. In shapeless you have to define foldLeft's handler as set of generic implicits, that can process generic input (like T or U).

You can reuse my f object to combine any parsers in typesafe way (you can combine even different types here - that's fine).

Second, less generic, way is:

implicit class as2[A, B](t: Parser[A ~ B]){ def ^^^^[T] (co: (A, B) => T) = t map {tt => val (a ~ b) = tt; co(a, b)} }
implicit class as3[A, B, C](t: Parser[A ~ B ~ C]){ def ^^^^[T] (co: (A, B, C) => T) = t map {tt => val (a ~ b ~ c) = tt; co(a, b, c)} }
implicit class as21 ...


scala> val p = foo ~ bar ~ car ^^^^ Record
p: MyParser.Parser[Record] = Parser ()

scala> parseAll(p, "foo bar car").get
res53: Record = Record(foo,bar,car)

It's not so cool, but doesn't require external libraries.

Related Query

More Query from same tag