/ / caseクラスへのパーサコンビネータの適用 - scala、パーサコンビネータ

パーサーコンビネータをcaseクラスに適用する - scala、parser-combinators

私はScalaの使い方を見ています パーサコンビネータ 文字列を解析します(改行なし、考案例)。

文字列は、別々に抽出してケースクラスを生成したいさまざまな部分で構成されています。

case class MyRecord(foo: String, bar: String, baz: String, bam: String, bat: String)

object MyParser extends scala.util.parsing.combinator.RegexParsers {

val foo: Parser[String] = "foo"
val bar: Parser[String] = "bar"
val baz: Parser[String] = "baz"
val bam: Parser[String] = "bam"
val bat: Parser[String] = "bat"

val expression: Parser[MyRecord] =
foo ~ bar ~ baz ~ bam ~ bat ^^ {
case foo ~ bar ~ baz ~ bam ~ bat => MyRecord(foo, bar, baz, bam, bat)
}

}

これは完全にうまく機能しますが、一致した結果の一部を分解しないでケースクラスに直接適用する方法はありますか?

val expression: Parser[MyRecord] =
foo ~ bar ~ baz ~ bam ~ bat ^^ MyRecord

さらに詳しい情報: 私が解析する文字列は非常に長く複雑です(実際には、長い複雑な文字列でいっぱいになったファイルです)ので、正規表現に変更することは問題外です。

回答:

回答№1は5

それは可能です 無形2 としょうかん。与えられたために:

 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)

genericを使ってパーサを組み合わせることができます foldRight~

 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)
.foldRight(success(HNil))(f).map(Generic[Record].from)

結果:

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

P.S組み込みのスカラ機能の問題は、それらが構築したことです。 ~トラバースが困難でタプルにフラット化された、ベースの型付きバイナリツリー。 Shapelessはこの問題を解決します - それはそれ自身を持っています ::ベースの二分木 HListこれは似ていますが、タプルやケースクラスへの変換(おそらくマクロベース)のような興味深い操作があります。 foldLeft Shapeless-hlistとfor-jamhension(を展開する flatMap それらはモナド的な性質を持っているのでパーサーを組み合わせる)。形のないあなたが定義する必要があります foldLeft一般的な暗黙の集合としてのハンドラ T または U)。

あなたは私のものを再利用できます f タイプパーフェクトな方法でパーサーを結合するためのオブジェクト(あなたはここでも異なるタイプを結合することができます。


第二に、あまり一般的ではない、方法は次のとおりです。

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)

それほどクールではありませんが、外部ライブラリを必要としません。