5

私はscalaの「>>」について少し混乱しています。ダニエルは、xmlを解析するScalaパーサーコンビネーターで言った?以前のパーサーからの結果に基づいてパーサーベースをパラメーター化するために使用できること。誰かが私にいくつかの例/ヒントを教えてもらえますか?私はすでにscaladocを読みましたが、それでも理解できません。

ありがとう

4

2 に答える 2

16

私が言ったように、それはパーサーをパラメーター化するのに役立ちますが、それを明確にするために例を見ていきましょう。

数字の後に単語を解析する単純なパーサーから始めましょう。

def numberAndWord = number ~ word
def number        = "\\d+".r
def word          = "\\w+".r

RegexParsersの下では、これは「3つの果物」のようなものを解析します。

さて、これらの「n個の物」が何であるかのリストも必要だとしましょう。たとえば、「3つの果物:バナナ、リンゴ、オレンジ」。それを解析して、どうなるか見てみましょう。

まず、「N」個を解析するにはどうすればよいですか?たまたま、次のようなrepN方法があります。

def threeThings = repN(3, word)

これは「バナナアップルオレンジ」を解析しますが、「バナナ、アップル、オレンジ」は解析しません。セパレータが必要です。それを提供するものがありrepsepますが、それでは私が望む繰り返しの数を指定することはできません。それでは、セパレータを自分で提供しましょう。

def threeThings = word ~ repN(2, "," ~> word)

わかりました、その言葉。これで、次の3つの例について、例全体を記述できます。

def listOfThings = "3" ~ word ~ ":" ~ threeThings
def word         = "\\w+".r
def threeThings  = word ~ repN(2, "," ~> word)

3で「N」を修正していることを除けば、そのような作業です。ユーザーにいくつ指定させたいのです。そして、それは、(そして、はい、それはのためです)>>としても知られているところです。まず、変更しましょう:intoflatMapParserthreeThings

def things(n: Int) = n match {
  case 1          => word ^^ (List(_))
  case x if x > 1 => word ~ repN(x - 1, "," ~> word) ^^ { case w ~ l => w :: l }
  case x          => err("Invalid repetitions: "+x)
}

を強制的に返すため、これは予想よりも少し複雑ですParser[List[String]]。しかし、どうすればパラメータを物事に渡すことができますか?つまり、これは機能しません:

def listOfThings = number ~ word ~ ":" ~ things(/* what do I put here?*/)

しかし、次のように書き直すことができます。

def listOfThings = (number ~ word <~ ":") >> {
  case n ~ what => things(n.toInt)
}

これでほぼ十分ですが、私が負けnて、what「リスト(バナナ、リンゴ、オレンジ)」のみが返され、必要な数とその数は返されません。私はこのようにそれを行うことができます:

def listOfThings   = (number ~ word <~ ":") >> {
  case n ~ what => things(n.toInt) ^^ { list => new ~(n.toInt, new ~(what, list)) }
}
def number         = "\\d+".r
def word           = "\\w+".r
def things(n: Int) = n match {
  case 1          => word ^^ (List(_))
  case x if x > 1 => word ~ repN(x - 1, "," ~> word) ^^ { case w ~ l => w :: l }
  case x          => err("Invalid repetitions: "+x)
}

最後のコメントです。「どういう意味flatMapですか?それはモナド/読解のためのものではありませんか?」と自問したかもしれません。なぜ、はい、そしてはい!:-)これが別の書き方listOfThingsです:

def listOfThings   = for {
  nOfWhat  <- number ~ word <~ ":"
  n ~ what = nOfWhat
  list     <- things(n.toInt)
}  yield new ~(n.toInt, new ~(what, list))

によって実装されていないScalan ~ what <- number ~ word <~ ":"を使用しているため、私は行っていません。しかし、これを書く別の方法があります。これは、まったく同じセマンティクスを持っていませんが、同じ結果を生成します。filterwithFilterParsers

def listOfThings   = for {
  n    <- number
  what <- word
  _    <- ":" : Parser[String]
  list <- things(n.toInt)
}  yield new ~(n.toInt, new ~(what, list))

これは、 「モナドはいたるところにある」という主張が何かを持っているのではないかと考える人さえいるかもしれません。:-)

于 2011-11-02T17:54:53.070 に答える
5

このメソッド>>は、パーサーの結果が与えられた関数を受け取り、それを使用して新しいパーサーを構築します。前述のように、これを使用して、前のパーサーの結果に基づいてパーサーをパラメーター化できます。

次のパーサーは、n + 1整数値の行を解析します。最初の値nは、従うべき値の数を示します。nこの最初の整数が解析され、次にこの解析の結果を使用して、さらに整数を解析するパーサーが構築されます。

パーサーの定義

次の行は、。を使用して整数を解析できることを前提としていますparseInt: Parser[Int]。最初に整数値を解析し、次にパーサーの結果を形成する追加の整数を解析するためnに使用します。したがって、イニシャルはパーサーによって返されません(ただし、返されるリストのサイズです)。>>nn

def intLine: Parser[Seq[Int]] = parseInt >> (n => repN(n,parseInt))

有効な入力

1 42
3 1 2 3
0

無効な入力

0 1
1
3 42 42
于 2011-11-02T11:50:53.770 に答える